Star Ratings With Very Little CSS

Feb 1 2012
36

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

Subscribe to The Thread

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

  2. fromanywhere

    Hmm…
    https://img.skitch.com/20120202-tdahxwtcyf1fdag65uwh2iybmd.jpg

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

    • fromanywhere

      <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. I love this idea!

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

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

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

  6. Luke

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

  7. Heiko

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

  8. Paul Nicholls

    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

    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. a gift ;)

    Unicode symbol map bookmarklet similar to “copypaste”

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

  12. BrianMB

    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!

    • BrianMB

      ugh.. if <select> is involved

  13. Alfred Larsson

    looks like five squares for me. chrome 15

  14. Chad

    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. I will use it on my site. Thanks!

  16. This would be very easy with SVG.

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

  18. DanaB

    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

    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

    Very good..

    Thank you

Speak, my friend

At this moment, you have an awesome opportunity* to be the person your mother always wanted you to be: kind, helpful, and smart. Do that, and we'll give you a big ol' gold star for the day (literally).

Posting tips:
  • You can use basic HTML
  • When posting code, please turn all
    < characters into &lt;
  • If the code is multi-line, use
    <pre><code></code></pre>
Thank you,
~ The Management ~