<h1>Pure CSS Star Rating System!!</h1>
<p>Using a sort of <strong>"previous sibling"</strong> selector</p>
<div class="rating">
  <!--elements are in reversed order, to allow "previous sibling selectors" in CSS-->
  <input aria-flowto="rating0" class="rating__input" type="radio" name="rating" value="5" id="rating5">
  <label class="rating__label" for="rating5">☆
    <span class="rating__star">5 Stars</span> 
  </label>
  
  <input aria-flowto="rating5"  class="rating__input" type="radio" name="rating" value="4" id="rating4">
  <label class="rating__label" for="rating4">☆
    <span class="rating__star">4 Stars</span> 
  </label>
  
  <input aria-flowto="rating4" class="rating__input" type="radio" name="rating" value="3" id="rating3">
  <label class="rating__label" for="rating3">☆
    <span class="rating__star">3 Stars</span> 
  </label>
  
  <input aria-flowto="rating3" class="rating__input" type="radio" name="rating" value="2" id="rating2">
  <label class="rating__label" for="rating2">☆
    <span class="rating__star">2 Stars</span> 
  </label>
  
  <input aria-flowto="rating2" class="rating__input" type="radio" name="rating" value="1" id="rating1" aria-flowto="rating2">
  <label class="rating__label" for="rating1">☆
    <span class="rating__star">1 Stars</span> 
  </label>
  
  <input aria-flowto="rating1" class="rating__input" type="radio" name="rating" value="0" id="rating0">
  <label class="rating__label rating__label--hidden" for="rating0">
    <span class="rating__star">Not rated yet </span>
  </label>
    
</div>
/*shows the stars side by side, centered, and in reverse order than the HMTL*/
.rating {
  display: flex;
  flex-direction: row-reverse;
  justify-content: center;
  border: 3px dashed #333;
  padding: 1em;
}

/*hides the radio buttons by forcing them out of the viewport*/
.rating__input{
  position: absolute; 
  left: -100vw;
}
/*hides label for 0 (unset)star rating */
.rating__label--hidden{
  display:none;
}

/* hides spans from sighted users */
.rating__star{
  position: absolute; left: -100vw;
  font-size: 1px
}

.rating:hover,
.rating:focus-within,
.rating:active {
  border-color: yellow;
}

/*style the empty stars, sets position:relative as base for pseudo-elements*/
.rating__label {
  position: relative;
  width: 1.1em;
  font-size: 15vw;
  color: #FFD700;
  cursor: pointer;
}

/* sets filled star pseudo-elements */
.rating__label::before{ 
  content: "\2605";
  position: absolute;
  opacity: 0;
}

/*overlays a filled start character to the hovered element and all previous siblings*/
.rating__label:hover:before,
.rating__label:hover ~ .rating__label:before {
  opacity: 1 !important;
}

/*overlays a filled start character on the selected element and all previous siblings*/
.rating__input:checked ~ .rating__label:before{
  opacity:1;
}

/*when an element is selected and pointer re-enters the rating container, selected rate and siblings get semi transparent, as reminder of current selection*/
.rating:hover > .rating__input:checked ~ .rating__label:before{ opacity: 0.4; }

/*just aesthetics*/
body{ background: #222225; color: white;}
h1, p{ text-align: center;}
p{ font-size: 1.2rem;}
@media only screen and (max-width: 600px) {
  h1{font-size: 14px;}
  p{font-size: 12px;}
}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.