How does this CSS star rating system work? (confusing selectors)

I ran across an example of a CSS star rating system.

Could someone help me understand how it works?

Namely, what does this selector target:

.reviewer__stars input:checked ~ label { color: #FFC40E; }

and what does this selector target:

.reviewer__stars input + label:hover, .reviewer__stars input + label:hover ~ label {
  color: #ffdd74;
}

Here’s the complete code:

<!doctype html>
<html>
  <head>
    <meta charset='utf-8'>
    <title>Star rating</title>
    <style>
      .reviewer__stars {
        display: flex;
        justify-content: center;
      }

      .reviewer__stars input { display: none; }
      .reviewer__stars input:checked ~ label { color: #FFC40E; }
      .reviewer__stars input + label { font-size: 0; }

      .reviewer__stars input + label:before {
        content: '\2605';
        font-size: 2rem;
      }

      .reviewer__stars input + label[for="star5"] { order: 5; }
      .reviewer__stars input + label[for="star4"] { order: 4; }
      .reviewer__stars input + label[for="star3"] { order: 3; }
      .reviewer__stars input + label[for="star2"] { order: 2; }
      .reviewer__stars input + label[for="star1"] { order: 1; }

      .reviewer__stars input + label:hover, .reviewer__stars input + label:hover ~ label {
        color: #ffdd74;
      }
    </style>
  </head>

  <body>

    <form action="/reviews/5a68596aa4e0c32fd867be7c" class="reviewer" method="post">
      <div class="reviewer__meta">
        <div class="reviewer__stars">
          <input id="star5" name="rating" required="required" type="radio" value="5">
          <label for="star5">5 Stars</label>

          <input id="star4" name="rating" required="required" type="radio" value="4">
          <label for="star4">4 Stars</label>

          <input id="star3" name="rating" required="required" type="radio" value="3">
          <label for="star3">3 Stars</label>

          <input id="star2" name="rating" required="required" type="radio" value="2">
          <label for="star2">2 Stars</label>

          <input id="star1" name="rating" required="required" type="radio" value="1">
          <label for="star1">1 Stars</label>
        </div>
      </div>
    </form>
  </body>
</html>
3 Likes

Wow, that’s clever. Not something I’d have been able to come up with.

The general sibling selector - the tilde - selects label elements that follow the input that is checked as ordered in the HTML, not the rendered view as ordered by flex.

The adjacent sibling selector - the plus - selects label elements that immediately follow an input.

★★★★★

3 Likes

That will style any label elements that are following siblings of a checked input.

That basically says that when you hover a label element please style this one and all label elements that follow that are siblings.

The flex order property reverses the visual order of the html so that when you hover number 5 all the previous stars will light up. This effect had to be achieved by more complicated means before you could re-order with flex as you would be stuck with number 5 star being the number 1 star.

It’s a nice solution to an old problem.

5 Likes

Ahhh… which is why he reverses the order, right? As visually he wants the stars up to and including the clicked star to be styled yellow, but in coding-terms only the reverse is possible.

Got it.

Thanks for the comprehensive explanation guys :slight_smile:

4 Likes

Paul, seriously man, you are ahead of your time!

4 Likes

Yes exactly :slight_smile:

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.