Star ratings are one of those classic UX patterns that everyone has tinkered with at one time or another. I had an idea get the UX part of it done with very little code and no JavaScript.
The markup uses the unicode entity for a star (☆) right in it. If you have a UTF-8 charset that should be no big deal. Alternatively you could use ☆ (Calculator for that kind of thing). You could use as many stars as you like:
<div class="rating">
<span>☆</span><span>☆</span><span>☆</span><span>☆</span><span>☆</span>
</div>
Now we need to flop out that “hollow” star with a “solid” star on hover (Gallery for finding those sorts of characters). Easy, just drop a pseudo element of a solid star (★) over it on :hover
.rating > span:hover:before {
content: "\2605";
position: absolute;
}
Just by virtue of being it being absolutely positioned, the top: 0; left: 0;
are implied (in modern browsers, anyway). So the solid star just sits directly on top of the hollow star. You could even change the color or size if you wished.
But what we have so far only works on individual stars. The UX pattern demands that all the stars be filled in. Fo instance, if we hover over the 4th star, the 4th star becomes solid, but also the 1st, 2nd, and 3rd.
Through CSS, there is no way to select a preceding child element. However, there is a way to select succeeding child elements, through the adjacent or general sibling combinators. If we literally reverse the order of the characters, then we can make use of the general sibling combinator to select all the stars that appear before the hovered star visually, but after the hovered star in the HTML.
.rating {
unicode-bidi: bidi-override;
direction: rtl;
}
.rating > span:hover:before,
.rating > span:hover ~ span:before {
content: "\2605";
position: absolute;
}
That’s it! The whole star ratings UX pattern with very little code. Here’s the entire bit of CSS to make it work:
.rating {
unicode-bidi: bidi-override;
direction: rtl;
}
.rating > span {
display: inline-block;
position: relative;
width: 1.1em;
}
.rating > span:hover:before,
.rating > span:hover ~ span:before {
content: "\2605";
position: absolute;
}
And here’s a Dabblet if you wanna mess with it.
Actual Usage
Chances are, JavaScript is going to be involved with rating stars anyway. When a user clicks a star, the rating is reported back via Ajax, and the widget itself gains a class to permanently display their selected number of stars. With JavaScript already involved, wouldn’t it be OK to lean on it for flip-flopping classes around on the stars to make them work? If your app is absolutely dependent on JavaScript to work, then sure, that’s fine. If you are interested in building a website that still works without JavaScript, then these Star Ratings are going to need more work. You should look into Lea Verou’s example which uses radio buttons, which could be a part of a form that can be submitted to “rate” whatever it is without JavaScript.
Others
After first sharing this on Twitter, a couple of other folks took a crack at it in slightly different ways. @dmfilipenko‘s Dabblet. @mprogano’s Dabblet
partially broken in Safari 5.1.2: http://cl.ly/DqpH
Hmm…
https://img.skitch.com/20120202-tdahxwtcyf1fdag65uwh2iybmd.jpg
Also, i think, it’s better to use , semantically, no?
<ul>, sorry
For that particular issue, turns out it’s best to at least use
left: 0;
for the absolutely positioned filled star.And I’d say no on the unordered list. If anything, an ordered one, but I’d say it’s just some stars you can click, it’s not a “list”.
I love this idea!
If it were me, I’d tack on “cursor:pointer” to the :hover state.
Yes that would be great!
It’s actually off a few pixels in the Chrome (Mac) too.
Nice article. This is very Great to share this useful post. thanks for the share.
I think it won’t work with mobile safari on touch like it does on mine
It’s an awesome technique, but I also get that pixel-offset in Firefox 10 on OS X.
Same here. I’m using Firefox 10 on Ubuntu (Linux)
FYI:
top: 0; left: 0;
are never implied. If an element is positioned absolutely, but a horizontal or vertical position is not specified, the element will take the horizontal or vertical position it would have had if the element would have been statically positioned (i.e. in flow).This is the case for all current browsers. (It works for old IE versions as well, but not completely: old IE has issues with absolutely positioned inline elements.)
See also: CSS 2.1: Visual formatting model details – 10.6.4 : Absolutely positioned, non-replaced elements
Extended to use transparent radio buttons to capture and preserve state without needing any JS:
http://dabblet.com/gist/1709019
I’ve only tested this in Chrome, but consider it a proof-of-concept. Will probably require some JS to support old browsers, but it’s a start.
I just tested it in Firefox 9, and it works perfectly there too. Anyone tested it elsewhere?
You gotta save it as a new Dabblet
Ah – I managed to copy the wrong URL. I did save it as a new dabblet:
http://dabblet.com/gist/1722368
Nice Tip ! but do you know why the stars are so ugly in Chrome on Windows
How to make half star active? if i want to give 3.5 star
a gift ;)
Unicode symbol map bookmarklet similar to “copypaste”
http://panmental.de/symbols/info.htm
Someone mentioned semantics earlier, and this only becomes semantic IMO if is involved.
Otherwise, this is awesome if you don’t require a star treatment outside of what an available typeface provides!
ugh.. if <select> is involved
looks like five squares for me. chrome 15
This would be the perfect use case of the not-yet-available
:nth-letter(n)
instead of all those spans.If you’re seeing squares it means the system font being rendered in your browser does not support the glyphs at those code points mentioned in the article.
I’m relatively new to the web development scene and I’m having a hard time understanding why avoiding JS with CSS is important. Are users running browsers with JS disabled? That seems very unlikely to me but again, I’m inexperienced in this space.
I will use it on my site. Thanks!
This would be very easy with SVG.
How’s that?
There’s no need to reverse direction to rtl.
See this Dabblet.
Please could you explain how you’ve managed to replicate Chris’ example without reversing the direction to ‘Right-To-Left’? I’ve read the Dabblet but I don’t quite understand what you did there, mate.
Nice solution without rtl!
The only issue is that because .rating is a block element, hovering over a part of the div which is not a star (e.g. Putting your mouse vertically in line with the stars, but on the far left of the page) results in all the stars going gold.
Great article. These are good for experiment but I’ll stick with the jQuery ones.
If the goal is merely minimal css, you could get rid of the .rating selector and it’s and add float: right to each span. Another way of flipping around the order. A by product being you would lose the centering….
Neat technique!
Props Chris, you’re so wicked creative with CSS. I would’ve never come up with this solution.
Though, as mentioned in the comments. Aren’t there browser compatibility issues when you’re using the Unicode symbol for a star instead of using an image?
– Rick
It’s a little annoying that the cursor flickers between text and pointer (I’m using chrome) while hovering over the stars. Maybe wrap each one with a div and set the cursor to something consistent?
It does not work in Windows XP. It however works on Windows Vista and Windows 7 because they have bigger / more updated charsets.
Thanks for the fantastic posts very informative and very usefull for us. Thanks for sharing keep posting.
Very good..
Thank you
Hi,
I don’t see stars. :)
Nice! This is really lightweight!
I like it, I try tu use it.
thanks
Here’s my implementation: http://pressedweb.com/sandbox/star_ratings
All CSS. Saves states. Falls back all the way to IE6. Easily add on as many or few stars as you need.
That’s a neat use of :target. One thing to note, that always seems to bite me in the ass when I want to do something cool functionality-wise with :target, is that you can’t prevent the page-jumpdown when the URL hash changes with just CSS (at least as far as I know). So if there is enough page content so that the page scrolls, when clicking the page will jump so that the star is butted up against the top edge.
When trying to implement click/toggle functionality through CSS, I’m a bigger fan of the checkbox/radio button hack. Lea Verou’s use it: http://lea.verou.me/2011/08/accessible-star-rating-widget-with-pure-css/
And I wouldn’t call hers a hack either, since selecting a choice of stars is basically what radio buttons do.
Ah curses. You’re absolutely right. Thanks for reminding me. I don’t realize it’s jumping to that page anchor when I’m testing it without it being surrounded by content.
Her solution is good moving forward (especially once IE9/10 are forced on people), but the fallback in 8 and below are ugly radio buttons and a text label.
Seems like her solution + using an image in the label + masking the radio button with the label + linking the label to the radio button = solution. I’m 99% sure that’d be the best solution and with some positioning TLC for IE6+ it’d become a standard.
Very cool technique that we can use on our website. Thanks!
I would have never thought of something like this – awesome solution for it!
Made my own little mods over at http://dabblet.com/gist/1817473 which mainly consists of some design changes (initially dots instead of stars) and also the removal of “unicode-bidi” since I don’t have a clue what it does.
this tricks are very good i use them in my site thanks for sharing them with us
it doesnt support for ie6, right? because in my pc, I tested in ie6, but failed. which version of ie browser will can be use?
Cool idea, but it’s accessibility is somewhat limited. Screen reader will not say: rating 4 stars, but: star star star star hollow star (if it even knows how to handle the difference between different star characters, which I doubt). Bots neither can make sense out of it. Also for human visitors, can you be sure those stars still make sense, even if their layout gets broken, e.g. if CSS is off or screen very small?
I prefer the old school patter of using numbers for the rating, and then substituting them on the fly with a proper number of stars, and that’s easier to do with background images.
Another alternative to radio buttons is just an anchor on each star which includes a query string for php to save the rating to the database. In fact I think anchors should be used instead of spans and Javascript can prevent default click event.
How to increase the size of the Star.. I tried with
<h1>
But it takes line break.. Kindly suggestYou can specify font-size in rating class
How to get red colored star??
just add a color attribute to the .rating > span:hover:before, .rating > span:hover ~ span:before
How about putting radio buttons inside of labels: http://codepen.io/thelucid/pen/JacHC
I still do not understand
How can I change color inside of the star?
How can I change color inside of the star?