Rating stars with memoization without any JavaScript

The idea is pretty simple - a rating element that will:

  • Display simple and clear (we'll use stars)
  • Display general state of rating
  • Be interactive
  • Have memoization (will remember last choice)
  • Keep value in input for future submit by form

Step 1: Creating interactive stars wireframe

We’ll use a container that will have inside overall progress of rating, and one element for each star.

<div class="stars">
  <div class="rating" style="width:65%"></div>
  <i></i>
  <i></i>
  <i></i>
  <i></i>
  <i></i>
</div>

with styles

.stars{
  width: 130px;
  height: 26px;
  background: url(http://sandbox.bumbu.ru/ui/external/stars.png) 0 0 repeat-x;
  position: relative;
}

.stars .rating{
  height: 26px;
  background: url(http://sandbox.bumbu.ru/ui/external/stars.png) 0 -26px repeat-x;
}

.stars i{
  display: none;
  position: absolute;
  top: 0;
  left: 0;
  height: 26px;
  width: 130px;
  cursor: pointer;
}
.stars:hover i{
  display: block;
}
.stars i:hover{
  background: url(http://sandbox.bumbu.ru/ui/external/stars.png) 0 -52px repeat-x;
}

.stars i + i{width: 104px;}
.stars i + i + i{width: 78px;}
.stars i + i + i + i{width: 52px;}
.stars i + i + i + i + i{width: 26px;}

Actually here each italic element (<i>) isn’t quite one star. In order to make hovering stars to behave as each star knows about previous one, each italic element is a group of  stars.

The result will look like this:

Step 2: Use input elements for value storage

In this case we’ll need radio inputs as they have property to keep only one value at one given time. And as we cann’t style input values in all browsers, we’ll use labels for this.

Replacing italic elements with labels:

<div class="stars">
  <div class="rating" style="width:65%"></div>
  <label for="star5"></label>
  <label for="star4"></label>
  <label for="star3"></label>
  <label for="star2"></label>
  <label for="star1"></label>
  <div class="radios">
    <input type="radio" name="rating" id="star1" value="1">
    <input type="radio" name="rating" id="star2" value="2">
    <input type="radio" name="rating" id="star3" value="3">
    <input type="radio" name="rating" id="star4" value="4">
    <input type="radio" name="rating" id="star5" value="5">
  </div>
</div>

The style for this is the same as in previous example, but all italic elements where replaced with label elements.

Now when we choose any element, the corresponding radio element will be marked as checked (later we’ll hide radio inputs).

Step 3: Display visually which star is selected

In order to do that we’ll use pseudo property :checked of radio inputs (that’s why this step will not work in old browsers).

We have to order elements in such a way that input is followed by its label.

<div class="stars">
  <div class="rating" style="width:65%"></div>
  <input type="radio" name="rating" id="star5" value="5">
  <label for="star5"></label>
  <input type="radio" name="rating" id="star4" value="4">
  <label for="star4"></label>
  <input type="radio" name="rating" id="star3" value="3">
  <label for="star3"></label>
  <input type="radio" name="rating" id="star2" value="2">
  <label for="star2"></label>
  <input type="radio" name="rating" id="star1" value="1">
  <label for="star1"></label>
</div>

Add to the css this property:

.stars input:checked + label{
  display: block;
  background: url(http://sandbox.bumbu.ru/ui/external/stars.png) 0 -52px repeat-x;
}

Now our rating should look like this:

Final step

The only thing that we have to do now is to hide inputs. So the result will look like this: