Star-rating with simple animations (the saga continues)

Andrew Bone - Jul 7 '21 - - Dev Community

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

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .