I don't know if you've all noticed but there have been a lot of star rating posts being published on Dev these past few days. Including an entry from me. The main problem with my entry was, that while it was accessible, it was a little boring. Now I know star ratings need to be functional so I won't be doing anything crazy, like using one giant star, but I will be adding some simple animations.
The saga so far
If you want to read through the articles written so far check out. @inhuofficial, @lapstjup, @madsstoumann, @afif and @siddharthshyniben. If you'd like to throw your own hat into the ring with a different way to achieve a star rating (it doesn't even have to be with web tech) feel free to write a post and let one of us know! 😊
The code
I'm not going to change my html, if it ain't broke; don't fix it. So if you want to look at the html and the logic behind it you'll need to have a look at my last post.
The animations
I didn't want anything to excessive so I'll be adding a little shake and pulse animation when a new star is selected.
The shake
The shake is a transform rotate which is in a keyframe this allows us to have a more complex animation.
.star-rating>input:checked+label>span.star {
animation: shake 820ms cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
transform: rotateZ(0);
}
@keyframes shake {
10%,
90% {
transform: rotateZ(-1deg);
}
20%,
80% {
transform: rotateZ(2deg);
}
30%,
50%,
70% {
transform: rotateZ(-3deg);
}
40%,
60% {
transform: rotateZ(3deg);
}
}
The pulse
The pulse is slightly more complex, but only slightly. We have to use a before
and give it our star as its content, this is so our pulse can match the shape. After that we just scale our pseudo element and make it more transparent.
.star-rating>input:checked+label>span.star::before {
content: '★';
pointer-events: none;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
color: currentColor;
-webkit-text-stroke: 0;
animation: pulse 820ms cubic-bezier(0.36, 0.07, 0.19, 0.97) forwards;
transform: scale(1);
opacity: 0;
}
@keyframes pulse {
10% {
transform: scale(1);
opacity: 1;
}
90% {
transform: scale(3);
opacity: 0;
}
}
Prefers Reduced Motion
The aim is to keep this component accessible and part of that is supporting people that can't handle too much motion and thusly have the prefers-reduced-motion rule enabled in their browser.
It's pretty simple to add support for this. For our shake we can just set the animation back to initial, meaning it never plays, and for our pulse we can hide the entire before
element.
@media (prefers-reduced-motion) {
.star-rating>input:checked+label>span.star {
animation: initial;
}
.star-rating>input:checked+label>span.star::before {
display: none;
}
}
It really is that simple to implement prefers-reduced-motion
and it can be so helpful for many people.
The result
Where here it is, the result. As I said earlier the HTML and functionality haven't changed but now we have a little pizazz.
Signing off
As always if you have any questions or feedback please leave a comment and I'll take a look. It'd be great if you could have a look at the other posts on this topic too they're really good and everyone has a different take.
I do hope this sort of post is helpful, would you be interested if this became a regular thing? Maybe a monthly topic that had a few people posting their take?
Thank you so much for reading.
🧙♂️❤️❤️🦄🐘🧠🤖👾