I'm trying to make a 5 circle rating system using CSS and HTML only (see below image for what I'd like it to look like), but I'm not sure how to achieve this.
My initial idea was to make 5 circles and then somehow use them as a mask for a background colour that's the complete width of all 5 circles. So the first image has a width of 90% with a background colour of #4a494a
, while the second image has a width of 60% and again, a background colour of #4a494a
.
These circles are fixed so no interaction shall be needed to paint them.
Does anyone have any ideas on how I might do this?
You can set rated value with attribute data-value="..." . Value for this attribute must be a valid number value and less or equal of count of stars. If your value is a float, you can use special attribute data-round-func="round|ceil|floor" to set round function.
To create a circle we can set the border-radius on the element. This will create curved corners on the element. If we set it to 50% it will create a circle. If you set a different width and height we will get an oval instead.
There is not technically a way to draw a circle with HTML (there isn't a <circle> HTML tag), but a circle can be drawn. Show activity on this post. You can use border-radius property, or make a div with fixed height and width and a background with png circle.
You can do this by using a pseudo-element (.rating:after
) that is positioned on top of div.rating
. The .rating
has a linear-gradient
whose background-size
determines how much of the circle is filled and in .rating:after
there is a radial-gradient
which produces five circles that act like the masks).
I have used an animation to show how the circle gets filled as background-size
increases. You can set the required background-size
using JS (or any backend code that generates the rating element) and then add it via inline styles to the div.rating
.
Using this approach, even in between ratings (or ratings of any value like 3.65, 2.25, 1.85 etc) can be handled with ease by just calculating the required background-size
. I have added a few samples in the demo.
.rating {
position: relative;
height: 50px;
width: 250px;
background: linear-gradient(to right, black, black);
background-repeat: no-repeat;
background-position: 0px 0px;
background-size: 0px 100%;
}
.rating.auto-anim {
animation: fill-circle 5s ease infinite;
}
.rating:after {
position: absolute;
content: '';
height: 100%;
width: 100%;
background: radial-gradient(20px at center, transparent 7.5px, beige 9px);
background-position: 0px 0px;
background-size: 50px 100%;
border: 1px solid;
}
@keyframes fill-circle {
to {
background-size: 100% 100%;
}
}
<div class='rating auto-anim'></div>
<div class='rating' style="background-size: 50px 100%;"></div> <!-- rating of 1 -->
<div class='rating' style="background-size: 75px 100%;"></div> <!-- rating of 1.5 -->
<div class='rating' style="background-size: 121.25px 100%;"></div> <!-- rating of 2.25 -->
<div class='rating' style="background-size: 228.75px 100%;"></div> <!-- rating of 4.75 -->
<div class='rating' style="background-size: 177.25px 100%;"></div> <!-- rating of 3.65 -->
<div class='rating' style="background-size: 80.25px 100%;"></div> <!-- rating of 1.85 -->
<!--
Background Size Calculation Logic: Each circle is only 15px wide with 17.5px gap on either side
1 rating = 50px (for 1 circle)
1.5 rating = 50px (for 1 circle) + 17.5px (gap before 2nd circle on left) + 7.5px (.5 of 15px circle)
2.25 rating = 100px (for 2 circles) + 17.5px (gap before 3rd circle on left) + 3.75px (.25 of 15px circle)
4.75 rating = 200px (for 4 circles) + 17.5px (gap before 5th circle on left) + 11.25px (.75 of 20px circle)
3.65 rating = 150px (for 3 circles) + 17.5px (gap before 4th circle on left) + 9.75px (.65 of 20px circle)
1.85 rating = 50px (for 1 circle) + 17.5px (gap before 2nd circle on left) + 12.75px (.85 of 20px circle)
-->
This can be completed with quite a small and easy amount of CSS to be able to create the effect you need.
.rating {
direction: rtl;
text-align: center;
}
.rating > span {
display: inline-block;
position: relative;
box-sizing: border-box;
width: 20px;
height: 20px;
border: 1px solid black;
border-radius: 10px;
}
.rating > span:hover,
.rating > span:hover ~ span {
background: transparent;
}
.rating > span:hover:before,
.rating > span:hover ~ span:before {
content: "";
position: absolute;
left: -2px;
top: -2px;
background: gold;
width: 20px;
height: 20px;
border: 1px solid gold;
border-radius: 20px;
}
<div class="rating">
<span></span><span></span><span></span><span></span><span></span>
</div>
This is a variant of Star Ratings
developed by css-tricks.com. Click here to read more!
If you use some clever css along with some radio
inputs you can achieve this with pure css and html, while even keeping it interactive. Have a look at the fiddle I set up: https://jsfiddle.net/2rs79wsh/
#ratings {
font-size: 0;
}
#ratings * {
float: right;
}
#ratings input {
display: none;
}
#ratings label {
width: 20px;
height: 40px;
background-color: #ccc;
display: inline-block;
}
#ratings label:nth-of-type(even) {
border-top-left-radius: 20px;
border-bottom-left-radius: 20px;
margin-left: 10px;
}
#ratings label:nth-of-type(odd) {
border-top-right-radius: 20px;
border-bottom-right-radius: 20px;
margin-right: 10px;
}
#ratings input:checked ~ label {
background-color: red;
}
<div id="ratings">
<input type="radio" id="rating-10" name="rating" value="10">
<label for="rating-10"></label>
...
<input type="radio" id="rating-1" name="rating" value="1" checked=checked>
<label for="rating-1"></label>
</div>
The circles you see are the labels for the inputs. The order is reversed (by using float right), so you can use ~
selector to show the state of all the siblings coming after the checked one. The radio's are there to store the state and should even allow you to send any changes back by submitting this inside a form. Each circle consists of two labels, so depending on which halve of the circle you click you'll get a different score. The odd
/even
selectors moves the two halves together two make it look like a single circle.
Feel free to ask if anything is unclear!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With