Star Rating
Introduction
This star rating widget is implemented using only CSS, given AMP's restriction on custom JavaScript. It still has the key features of star rating components:
-
touch, mouse and keyboard accessibility
-
stars change color when the user mouses over them
-
once a selection is made, it "sticks"
-
clean scalable vector icons
-
screen reader friendly
Setup
Import the amp-form
component.
<script async custom-element="amp-form" src="https://cdn.ampproject.org/v0/amp-form-0.1.js"></script>
We also need the amp-mustache
component.
<script async custom-template="amp-mustache" src="https://cdn.ampproject.org/v0/amp-mustache-0.2.js"></script>
CSS for the star rating
This star rating implementation overlays "☆" Unicode characters precisely over radio buttons. Inline comments below describe the rules in detail.
<style amp-custom>
.rating {
--star-size: 3; /* use CSS variables to calculate dependent dimensions later */
padding: 0; /* to prevent flicker when mousing over padding */
border: none; /* to prevent flicker when mousing over border */
unicode-bidi: bidi-override; direction: rtl; /* for CSS-only style change on hover */
text-align: left; /* revert the RTL direction */
user-select: none; /* disable mouse/touch selection */
font-size: 3em; /* fallback - IE doesn't support CSS variables */
font-size: calc(var(--star-size) * 1em); /* because `var(--star-size)em` would be too good to be true */
cursor: pointer;
/* disable touch feedback on cursor: pointer - http://stackoverflow.com/q/25704650/1269037 */
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-tap-highlight-color: transparent;
margin-bottom: 1em;
}
/* the stars */
.rating > label {
display: inline-block;
position: relative;
width: 1.1em; /* magic number to overlap the radio buttons on top of the stars */
width: calc(var(--star-size) / 3 * 1.1em);
}
.rating > *:hover,
.rating > *:hover ~ label,
.rating:not(:hover) > input:checked ~ label {
color: transparent; /* reveal the contour/white star from the HTML markup */
cursor: inherit; /* avoid a cursor transition from arrow/pointer to text selection */
}
.rating > *:hover:before,
.rating > *:hover ~ label:before,
.rating:not(:hover) > input:checked ~ label:before {
content: "★";
position: absolute;
left: 0;
color: gold;
}
.rating > input {
position: relative;
transform: scale(3); /* make the radio buttons big; they don't inherit font-size */
transform: scale(var(--star-size));
/* the magic numbers below correlate with the font-size */
top: -0.5em; /* margin-top doesn't work */
top: calc(var(--star-size) / 6 * -1em);
margin-left: -2.5em; /* overlap the radio buttons exactly under the stars */
margin-left: calc(var(--star-size) / 6 * -5em);
z-index: 2; /* bring the button above the stars so it captures touches/clicks */
opacity: 0; /* comment to see where the radio buttons are */
font-size: initial; /* reset to default */
}
form.amp-form-submit-error [submit-error] {
color: red;
}
</style>
Usage
While this star rating widget is accessible via the keyboard, that doesn't happen without quirks:
- Click/tap the widget, then press up/down/left/right arrows. Unfortunately, in Firefox and Safari, keyboard arrows work backwards. This issue appears to be impossible to fix on non-Chrome-based browsers without using JavaScript, so stay tuned for the amp-rating component.
- Mouse over the stars to see the style change.
We'll use a set of radio buttons to take user input for the star ratings, because they are keyboard-accessible.
For desktop, it's nice to change the style of the previous stars when the user hovers their mouse over them. The only pure-CSS way to affect the style of previous elements onmouseover is to list them in reverse DOM order, which is why the <input>
elements below run from 5 to 1.
We want the form to submit as soon as the user makes a selection, without a Submit button. To do that, we'll set the on
attribute of the input
s to submit the form on change
.
The initial rating is determined by which radio button has the checked
attribute set. This is optional.
<form id="rating" method="post" action-xhr="https://amp.dev/documentation/examples/interactivity-dynamic-content/star_rating/set" target="_blank">
<fieldset class="rating">
<input name="rating" type="radio" id="rating5" value="5" on="change:rating.submit">
<label for="rating5" title="5 stars">☆</label>
<input name="rating" type="radio" id="rating4" value="4" on="change:rating.submit">
<label for="rating4" title="4 stars">☆</label>
<input name="rating" type="radio" id="rating3" value="3" on="change:rating.submit">
<label for="rating3" title="3 stars">☆</label>
<input name="rating" type="radio" id="rating2" value="2" on="change:rating.submit" checked="checked">
<label for="rating2" title="2 stars">☆</label>
<input name="rating" type="radio" id="rating1" value="1" on="change:rating.submit">
<label for="rating1" title="1 stars">☆</label>
</fieldset>
<div submit-success>
<template type="amp-mustache">
<p>Thanks for rating {{rating}} star(s)!</p>
</template>
</div>
<div submit-error>
<template type="amp-mustache">
Looks like something went wrong. Please try to rate again. {{error}}
</template>
</div>
</form>
Se as explicações nesta página não respondem a todas as suas perguntas, entre em contato com outros usuários de AMP para discutir seu caso de uso específico.
Ir para o Stack Overflow Falta explicar algum recurso?O projeto AMP incentiva fortemente sua participação e contribuições! Esperamos que você se torne um participante assíduo de nossa comunidade de código aberto, mas também agradecemos contribuições pontuais para problemas que você tenha particular interesse.
Editar amostra no GitHub-
Written by @sebastianbenz