Creating a fixed 5 circle rating using CSS/HTML
Asked Answered
M

5

5

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.

Circle Rating

rating 2

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?

Mohl answered 20/3, 2016 at 16:6 Comment(7)
By no interaction you mean that there would be no need to respond to user click/hover events and that the rating comes from backend?Intension
Your idea is interesting, but there are no masks in CSS, you can't just cut the circles out of an opaque square to show what's behind it as far as I know. I think I'd just create the circles separately and paint the one with the decimal point with a gradientOrthodontist
Yes @Intension that's correct.Mohl
And Thanks @TalyaS I will have a look into it. In the meantime, if anyone else knows of anything, please do let me know. Or if this can be simplified.Mohl
@TalyaS: CSS does have masks (but it is not widely supported). This however can be done using radial-gradient background instead of a mask.Intension
@Intension Yes I see that in your answer now. Very cool, wasn't aware this existed either :)Orthodontist
You can also you pseudo elements to create the "masks".Ramekin
I
6

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)
-->
Intension answered 20/3, 2016 at 16:17 Comment(2)
Thanks Harry that's exactly what I wanted, could you tell me what I need to change to make the circles 15px wide? I've tried a few things but it has just moved the circles closer together. Thanks once againMohl
@MoMartin: You just need to change the radius of the transparent part in the radial gradient (to half of the circle's diameter, which is, 7.5px here). The calculations would also change accordingly and I have made the necessary changes in the snippet.Intension
D
3

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!

Debauch answered 21/3, 2016 at 12:25 Comment(0)
G
1

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!

Gladygladys answered 20/3, 2016 at 16:30 Comment(0)
S
0

There should be a lot of snippet and codes out there for this here you can find what you are looking for, and if you want a bit of style I would liek you to check this out. From the first example the rating is being controlled by the width percentage style="width: 68%" on each divs.

Seldom answered 20/3, 2016 at 16:13 Comment(0)
R
0

You can do this fairly easily with psuedo elements: HTML

<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li class="half"></li>
</ul>

CSS

ul {
display:block;
}

li {
display:inline-block;
list-style: none;
width:20px;
height:20px;
border-radius:50%;
background-color:orange;
overflow:hidden;
position:relative;
}

li::after {
    position:absolute;
    content: '';
    background-color:rgba(0,0,0,.5);
    display:block;
    width:20px;
    height:20px;
    top:0;
    left:0;
}


li.half::after {
    left:-10px;
}

Fiddle https://jsfiddle.net/fz2qo82m/

You would simply adjust the class on the last circle (or last couple, you could add a none class if the rating is under 4 circles)

Ramekin answered 20/3, 2016 at 16:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.