Semantic HTML for a Simple 5-Star Rating System
I am going to deviate this week from the Json Object discussion, as I have not had any time to work on it. Instead, I wanted to share a technique you can use to write semantic HTML for a rating system. If you have ever used a site like Amazon.com or Yelp.com, then you are familiar with the star rating system (0 stars = worst rating, 5 stars = best rating). However, most rating systems do not do a good job when browser font-size or zoom changes, making them inaccessible. Also, most tend to use a different graphic for each rating, requiring up to 10 graphics to load. The technique I worked on this week, not only scales well, but only requires 2 graphics, and you can change the color of your ratings with simple CSS.
Step 1: Create 2 Images
First decide which size you want the image to normally be (for me this was 80px wide by 16px high); this is a 1 to 5 ratio, because I am going to use a 5 point rating system, which will play an important role for the size of each rating point symbol. Use a program like Photoshop to create an image with these dimensions and a transparent background. In a separate window create an 16 x 16 (or 1/5 of the default width you chose) transparent image and draw in the symbol you want to use for the rating point (I used black for the color of my symbol, but it is up to you). I used a star, but it doesn’t matter what you choose so long as the center is transparent and the symbol fills the dimensions. All spaces outside the symbol should be the background color of your page (this is white for my example page). Here is an example of my star:
Example 1: Star Graphics


The first graphic shows what “star.gif” looks like by default. The second show, the difference when a background color is applied. I choose red, but you can change it to whatever hex you prefer.
Next copy your 16×16 symbol image 5 times into the original image you created. You should have something that looks like the following:
Example 2: Rating Graphics


Example 2 is the first image we will need. I made the background yellow to show how easy it is to change. The second image we need is a background masking image used to cover the part of the rating inverse (if the rating is 1.5, then this will cover the other 3.5 of the symbols). The background should be the color of the site background (white for me), and the left-most pixels should all be the color of the symbols (black for me). This image should be taller and wider than the rating image, because it will need to scale as the browser does. I usually do 2x the original dimensions, which supports up to a +4 font-size. Therefore, the dimensions of my “ratingbg.gif” is 160×32px:
Example 3: Rating Background Graphics

The gray border is only here to show contrast so you can see what the image looks like. The small sliver of black on the left will be the line that marks the rating position inside of the symbols. This completes all the images and HTML you will need to get the rating system to work.
Step 2: Create Styles to Control the Ratings
Next we style the image tag to support our ratings. I suggest using classes, here are the styles I used:
Example 4: Rating Styles
img.rating { background: #FC0 url(/assets/img/bg/ratingbg.gif) 5em 0 no-repeat; /* specify your color; 5 em is the 5:1 ratio; and the url is wherever the ratingbg.gif is located */ font-size: 1.6em; /* this is the height of a single symbol; mine is 16px */ height: 1em; /* this will cause the image to scale as the font-size changes, default is 16px */ width: 5em; /* this the 5 to 1 ratio that I mentioned, but could be different if your symbols aren’t symetric */ } /* higher specificity than img.rating */ html body img.r9 { background-position: 4.5em 0; } html body img.r8 { background-position: 4.0em 0; } html body img.r7 { background-position: 3.5em 0; } html body img.r6 { background-position: 3.0em 0; } html body img.r5 { background-position: 2.5em 0; } html body img.r4 { background-position: 2.0em 0; } html body img.r3 { background-position: 1.5em 0; } html body img.r2 { background-position: 1.0em 0; } html body img.r1 { background-position: 0.5em 0; } html body img.r0 { background-position: 0 0; }
Step 3: Tie it all Together
Here is a rating of 2.5 in yellow, 1 in blue, and 4.5 in green:
Example 5: 3 Star Rating Variations



The image heights in this article are slightly off by a fraction, due to rounding issues with other styles inherited in this wordpress theme. I have also created a test page so you can play with the uncorrupted styles and view them in different browsers. Try to scale the font-size and see how nicely the images scale and the rating stays in the appropriate place.
Nice article! I never make use CSS to mask image. This article greatly shows it.
At most time when I make a rating system, I used 2 image. Each image has one star. One for unstarred and another one for starred. I put them in 2 nested divs as a background-image and let it repeat. The outer div shows all the gray stars and the inner div shows the gold stars.
PS: In the test page, without images, the rating just won’t show. Missing alt=”" maybe?
Comment by the DtTvB — December 19, 2007 @ 7:43 pm
DtTvB, thanks for commenting. I believe I fixed the issue you mentioned. The paths to the images were relative and should have been absolute. Let me know if you are still not seeing images.
Comment by admin — December 19, 2007 @ 7:50 pm
Ok, I see the images now. ;)!
Comment by the DtTvB — December 20, 2007 @ 1:43 am
Nice article. Another great use for CSS. I tried your testpage, however rescaling it would show a flaw, i.e. scaling larger than the background image would show the stars incorrectly (in FF 2.0.0.12). I would suggest using a background image 1px high and wide enough (say 1000px) to allow rescaling to enormous stars. Then having the background repeat-y. Having said this, I would like to thank you for sharing this idea, I am sure I will find a use for it in my future pages.
Comment by Giappe — March 17, 2008 @ 3:27 am