Grow your CSS skills. Land your dream job.

Star Ratings With Very Little CSS

Published by Chris Coyier

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;
}

View Demo

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

Comments

  1. Permalink to comment#

    partially broken in Safari 5.1.2: http://cl.ly/DqpH

  2. fromanywhere
    Permalink to comment#

    Hmm…

    http://img.skitch.com/20120202-tdahxwtcyf1fdag65uwh2iybmd.jpg

    Also, i think, it’s better to use , semantically, no?

    • fromanywhere
      Permalink to comment#

      <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”.

  3. Permalink to comment#

    I love this idea!

    If it were me, I’d tack on “cursor:pointer” to the :hover state.

  4. Permalink to comment#

    It’s actually off a few pixels in the Chrome (Mac) too.

  5. Permalink to comment#

    Nice article. This is very Great to share this useful post. thanks for the share.

  6. Luke
    Permalink to comment#

    I think it won’t work with mobile safari on touch like it does on mine

  7. Heiko
    Permalink to comment#

    It’s an awesome technique, but I also get that pixel-offset in Firefox 10 on OS X.

  8. Paul Nicholls
    Permalink to comment#

    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.

  9. Stefan Cova
    Permalink to comment#

    Nice Tip ! but do you know why the stars are so ugly in Chrome on Windows

  10. How to make half star active? if i want to give 3.5 star

  11. Permalink to comment#

    a gift ;)

    Unicode symbol map bookmarklet similar to “copypaste”

    http://panmental.de/symbols/info.htm

  12. BrianMB
    Permalink to comment#

    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!

  13. Alfred Larsson
    Permalink to comment#

    looks like five squares for me. chrome 15

  14. Chad
    Permalink to comment#

    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.

  15. Permalink to comment#

    I will use it on my site. Thanks!

  16. Permalink to comment#

    This would be very easy with SVG.

  17. Permalink to comment#

    Great article. These are good for experiment but I’ll stick with the jQuery ones.

  18. DanaB
    Permalink to comment#

    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!

  19. 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

  20. Aaron
    Permalink to comment#

    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?

  21. It does not work in Windows XP. It however works on Windows Vista and Windows 7 because they have bigger / more updated charsets.

  22. Thanks for the fantastic posts very informative and very usefull for us. Thanks for sharing keep posting.

  23. Sascha Metz
    Permalink to comment#

    Very good..

    Thank you

  24. Permalink to comment#

    Hi,

    I don’t see stars. :)

  25. Nice! This is really lightweight!

  26. Permalink to comment#

    I like it, I try tu use it.
    thanks

  27. Permalink to comment#

    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.

    • Permalink to comment#

      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.

  28. Permalink to comment#

    Very cool technique that we can use on our website. Thanks!

  29. Permalink to comment#

    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.

  30. Permalink to comment#

    this tricks are very good i use them in my site thanks for sharing them with us

  31. 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?

  32. Permalink to comment#

    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.

  33. michael
    Permalink to comment#

    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.

  34. How to increase the size of the Star.. I tried with <h1> But it takes line break.. Kindly suggest

  35. dfdfd
    Permalink to comment#

    How to get red colored star??

    • Anurag Agarwal
      Permalink to comment#

      just add a color attribute to the .rating > span:hover:before, .rating > span:hover ~ span:before

  36. Permalink to comment#

    How about putting radio buttons inside of labels: http://codepen.io/thelucid/pen/JacHC

  37. I still do not understand

  38. Mohammad
    Permalink to comment#

    How can I change color inside of the star?

  39. How can I change color inside of the star?

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".