Create clickable rating stars with only SASS and HTML
July 3, 2015
In May, Roy Tomeij wrote the article "Configurable star rating without JS". I was thinking how to do this using a font icon instead of a background image and make the stars clickable. I believe it would take less code to write, and it is. I had the code finished a couple of days later in May, but now I've finally have the time to post my solution. So here we go:
HTML structure
I place the radio buttons in reversed order in the DOM to be able to do the hover + checked state in the right order with SASS. For the star I created a font icon using Fontcustom and Sketch.
I also add a "remove rating" option to be able to reset the rating.
<div class="remove-rating-wrapper">
<input type="radio" name="4 stars" id="remove-rating">
<label for="remove-rating">Remove rating</label>
</div>
<div class="rating">
<input type="radio" name="4 stars" id="star-4">
<label for="star-4" class="icon-star"></label>
<input type="radio" name="4 stars" id="star-3">
<label for="star-3" class="icon-star"></label>
<input type="radio" name="4 stars" id="star-2">
<label for="star-2" class="icon-star"></label>
<input type="radio" name="4 stars" id="star-1">
<label for="star-1" name="4 stars" class="icon-star"></label>
</div>
First I hide the radio boxes using a negative margin. On the labels I add the class "icon-star", which triggers the icon font. Then I create a SASS map for the number of stars I want to show.
$stars-list: (
1,
2,
3,
4
);
.rating {
position: relative;
overflow: hidden;
height: 32px;
@include rating-stars($stars-list, 32px, $orange, #f5d76d, 85);
// Hide the radio buttons
[type="radio"] { margin-left: -19px; }
label { cursor: pointer; }
.icon-star { font-size: 3rem; }
}
The rating stars mixin is where it all happens, it contains 4 arguments:
- Number of stars
- star width
- hover color
- selected color
// Set hover + selected label for star rating
@mixin rating-stars($stars, $star-width, $c-hover, $c-selected) {
> label {
position: absolute;
top: 4px;
&:hover { color: $hover; }
}
// Loop through the stars to position them in the right order,
and set the hover + checked color
@for $i from 1 through length($stars) {
// position the stars in reversed order
> label:nth-of-type(n + #{$i}) {
left: ($star-width * length($stars)) - ($star-width * $i);
}
// Handle the hover
> label:nth-of-type(n + #{$i}):hover ~ label { color: $hover; }
// Set selected color on all label siblings based on the checked radio
> input[type="radio"]:nth-of-type(n + #{$i}):checked ~ label {
color: $selected;
}
}
}
Demo
And here a demo, as you can see it is not much code and it works in all latest browsers. I hope the article is meaningful to you.