Today we will be looking at making an SVG based star rating.
In our example, we will be using three types of stars. (Empty. Half, and full).
Then we will be showcasing some examples of how to use them to show a specific rating.
The end result, as you can see on this Codepen.
Creating the SVG set
As mentioned we will be using three versions, and we will be using SVG Sprites to accomplish this.
<svg id="stars" style="display: none;" version="1.1">
<symbol id="stars-empty-star" viewBox="0 0 102 18" fill="#F1E8CA">
<path d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218" />
</symbol>
<symbol id="stars-full-star" viewBox="0 0 102 18" fill="#D3A81E">
<path d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792 5.657 6.243.907-4.517 4.404 1.066 6.218" />
</symbol>
<symbol id="stars-half-star" viewBox="0 0 102 18" fill="#D3A81E">
<use xlink:href="#stars-empty-star" />
<path d="M9.5 14.25l-5.584 2.936 1.066-6.218L.465 6.564l6.243-.907L9.5 0l2.792" />
</symbol>
</svg>
As you can see we have the following:
- stars-empty-star: This is our has a very light gold background.
- stars-full-star: This is actually the same shape, but with a different color.
- stars-half-star: This is a combination of an empty star at the bottom, and a half star on top of it.
That's going to be our source, and we can use this in the following ways.
Using the SVG stars
The main question is, of course, how can we now showcase our stars?
Lets say you want to show a empty star:
<svg aria-hidden="true" focusable="false" class="rating">
<use xlink:href="#stars-empty-star" />
</svg>
Or a full star:
<svg aria-hidden="true" focusable="false" class="rating">
<use xlink:href="#stars-full-star" />
</svg>
Or even the half star:
<svg aria-hidden="true" focusable="false" class="rating">
<use xlink:href="#stars-half-star" />
</svg>
That works, awesome!
But now we want to make a 5-star rating component, and SVG's tend to crawl on top of each other.
So if we have the following code:
<!-- 2.5 Rating -->
<svg aria-hidden="true" focusable="false" class="rating">
<use xlink:href="#stars-full-star" />
<use xlink:href="#stars-full-star" />
<use xlink:href="#stars-half-star" />
<use xlink:href="#stars-empty-star" />
<use xlink:href="#stars-empty-star" />
</svg>
If all sits like this:
Hmm, weird? It only shows one star?
Correct!
So let's use CSS
to fix that.
use {
&:nth-child(2) {
transform: translate(20px);
}
&:nth-child(3) {
transform: translate(40px);
}
&:nth-child(4) {
transform: translate(60px);
}
&:nth-child(5) {
transform: translate(80px);
}
}
Every x child we give 20px offset position.
So now we get this:
You can find the rest of the combinations on the Codepen!
Thank you for reading, and let's connect!
Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter
Top comments (3)
It'd be so nice if we could just do
and just use an attribute to do these things.
Setting that aside, here's a few things I don't completely like about this code:
nth-child
andtransform
, you could just addx
andy
attributes to theuse
element.<defs>
block at the beginning of the document for readability.This is what I came up with after some tinkering:
Yeah, attribute nth-child would be a nice one, hey.
Your right could actually have swapped for x on the use. You know how you get into this code and debugging, and then it sticks, haha.
As for your one star, that's not completely true. Since you want dynamic colors based on the same, it's almost impossible to overwrite the color then or do the half stars.
I'll put this on my list to refactor to use the x instead of the nth-child.
Also, you could have defs and created fixed defs for each option so you can just use 1 single-use, but that's if you need all of them.
Half-stars can easily be done using a linear gradient with two stops at 50% (you can even move it around at random). As for the dynamic colours, I don't really get what you mean by that. Unless you want to change the actual shape of the star, almost everything can be done using CSS.