DEV Community

Cover image for Star-rating with simple animations (the saga continues)
Andrew Bone
Andrew Bone

Posted on

Star-rating with simple animations (the saga continues)

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);
  }
}
Enter fullscreen mode Exit fullscreen mode

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;
  }
}
Enter fullscreen mode Exit fullscreen mode

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;
  }
}
Enter fullscreen mode Exit fullscreen mode

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.
🧙‍♂️❤️❤️🦄🐘🧠🤖👾

Top comments (8)

Collapse
 
grahamthedev profile image
GrahamTheDev • Edited

In stark contrast to my post that started this all, this one might kickstart more ideas for interactivity. I am glad you used prefers-reduced-motion as some people may find animations startling. So from an accessibility point of view this one cuts the mustard. Just when I think this will end some upstart decides to restart everything, I am starting to think this will never end!

I will see myself out...

Collapse
 
link2twenty profile image
Andrew Bone • Edited

Yeah prefers-reduced-motion was all I really brought to the table, I think, but I do think it was an important thing to mention.

You boldened the t in upstart, so close 😉.

Collapse
 
grahamthedev profile image
GrahamTheDev

😉

Collapse
 
afif profile image
Temani Afif

Oh, you are fighting with animation now! You are using one of my superpower against me and you will regret it soon ...

Collapse
 
link2twenty profile image
Andrew Bone • Edited

I knew it was a risk 😉

Collapse
 
allthecode profile image
Simon Barker

Great improvement Andrew, your CSS is way above mine, I guess that's why I'm a full stack trogledite though 🤣

Collapse
 
link2twenty profile image
Andrew Bone

Haha, thanks. I really enjoy writing CSS 😁.

Collapse
 
link2twenty profile image
Andrew Bone

As with the last post I've converted this into a react component.