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>
Jeśli przedstawione tutaj wyjaśnienia nie odpowiadają na wszystkie pytania, skontaktuj się z innymi użytkownikami AMP, aby omówić daną przykładową realizację.
Przejdź do Stack Overflow Niewyjaśniona funkcja?Zdecydowanie zachęcamy do wzięcia udziału! Choć mamy nadzieję, że staniesz się stałym uczestnikiem naszej społeczności open source, to z wdzięcznością przyjmiemy również każdy jednorazowy wkład w kwestie, które są Twoją pasją.
Edytuj przykład na GitHub-
Written by @sebastianbenz