How to Make a CSS Sprite Powered Menu

We haven’t gone back to basics in a while.

Today’s tutorial will bring you through the process of building a slick menu using a single CSS sprite image. It’s a simple, but elegant solution for most websites. This was one of the design strategies that first helped me to start using smarter markup. For those of you just getting introduced to this technique today, hopefully you’ll have some similar results.

The end goal is to create a navigation menu that loads quickly, and does not require any dated JavaScript for hover effects. If you’re still using individual images for each menu item, it’s time to upgrade.

The Goal

This CSS sprite will keep HTTP requests down and increase load speed. For a more in depth explanation of CSS Sprites, take a look at Chris Coyier’s article on CSS Tricks. He goes into a wider variety of uses, but this tutorial will focus on getting the navigation done for simplicity’s sake.

The end result

Design the Menu

Breaking from the usual flow of tutorials, we’re going to take a look at part of the Photoshop process before hitting the code. This is in order to demonstrate a simple way of measurement and markers for the menu’s sprite design.

Love the Grid

Rulers and markers are your best friend when it comes to CSS sprites. To take advantage of these guides in Photoshop, turn on rulers through the View>Rulers option in the toolbar. Once rulers are active, you can create a new guide by click on the ruler and then dragging onto the composition area. These guide lines can be used to align your sprite. Alternatively, you can activate the grid overlay through View>Show>Grid.

Guides in Photoshop

In order for the positioning to work in CSS, you’ll need to know the rough coordinates of each menu item inside the sprite. I’ve found it easiest to pick a measurement system that it consistent instead of minimal.

To put it another way, I would much rather remember 100px, 200px, etc than 101px, 342px, etc. Blocking your sprite out in a logical grid also makes future changes significantly less painful, and often requires less adjustment. You can find the example sprite image that I use for this tutorial at the bottom of this post in the source files.

Structure with HTML

The code below will set up a basic menu structure for us to work with in CSS. Feel free to start a new file or insert into an existing menu.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

	<title>CSS Sprite Navigation</title>
	<link rel="stylesheet" href="css-sprites-nav.css" type="text/css" />

</head>

<body>

		<ul id="menu">
			<li class="home"><a class="selected" href="#">Home</a></li>
			<li class="about"><a href="#">About</a></li>
			<li class="contact"><a href="#">Contact</a></li>
		</ul>

</body>
</html>

A Brief Word on SEO

Our top navigation menu will be structured as a list to keep semantic code. Keep in mind that because these list items will only be displaying an image. The hidden overflow and negative text indent will hide any text from the user’s view. We do not want to leave them blank, because that would give search engines less content to crawl. Even though the images will have text, the search engine will not be aware of this unless we give it actual code to reference.

The Big Idea: As designs become more graphic intense, it is ok to use images (in moderation) as text replacement for elements like navigation, banners, button, etc. If you choose to do this, you still have to account for the search engines.

Position Images with CSS

Copy the code below into your CSS file for the project. An explanation will follow.

/* Everything CSS Sprite Menu */
	ul#menu{margin:0; padding:0; list-style:none; clear:both;}
		#menu li{overflow:hidden; text-indent:-9999px; display:inline; float:left; margin-right:10px;}
			#menu li a{background:url('images/menu-sprite.jpg') no-repeat; width:100%; height:100%; display:block;}

			/* Home Button */
			#menu li.home{width:115px; height:60px;}
				#menu li.home a{background-position:-5px -5px;}
				#menu li.home a:hover{background-position:-5px -75px;}
				#menu li.home a.selected{background-position:-5px -145px;}

			/* About Button */
			#menu li.about{width:120px; height:60px;}
				#menu li.about a{background-position:-125px -5px;}
				#menu li.about a:hover{background-position:-125px -75px;}
				#menu li.about a.selected{background-position:-125px -145px;}

			/* Contact Button */
			#menu li.contact{width:160px; height:60px;}
				#menu li.contact a{background-position:-250px -5px;}
				#menu li.contact a:hover{background-position:-250px -75px;}
				#menu li.contact a.selected{background-position:-250px -145px;}

Change Image with Background Position

The background-position CSS property allows you to specify a set of coordinates on the background image. The benefit of this is that you can load a single background image for a number of elements, but give individual ones their own coordinates. This property is the backbone of CSS sprites.

You’ll remember that we gave each menu list item its own class. This allows us to target them individually for background image coordinates. The background image has already been defined by the general anchor tag style, so the only change that needs to be made for each menu item is the positioning. Especially on larger projects, keeping down the number of redundant styles is key to keeping sanity.

Using this method, we created three unique states for the navigation:

  1. Default is displayed to start
  2. Hover is activated by mouseover
  3. Selected indicates the current page location. It can be activated by a special “selected” class assignment

Unless you’re building something out of the ordinary (e.g. multi-tiered menu), you’d have a hard time needing anything past these three states.

Wrapping Up

By this point you should have a menu driven by a single image. As Chris Coyier’s article brings up, this lowers HTTP requests and allows a smoother loading experience than a long list of bulky separate files for each element. Condensing is good for pages.

I’ve put together a ZIP file of source code and demo for further help. The example in the file is a little more comprehensive, but still follows the principles of this tutorial. Having any errors or confusion about the process? Leave a comment below and we’ll try to sort things out.

  • Stumble It!
  • Bookmark It!
  • Tweet it!

About Zach Dunn

Zach is a partner and interface designer at One Mighty Roar from Massachusetts, USA. Follow him on Twitter @zachdunn.

 

Discussion

  1. Eric B.

    January 26th, 2010 at 12:34 AM

    CSS sprites are really one of the best things ever that I have discovered! They’re not too hard to make, and make everything go much more quickly.

    I’m actually currently in the process of converting someone’s old navigation menu consisting of an image for each navigation menu item, an image for each hover state, using Javascript for a basic hover effect like the one in this demo. *shudder*

    Thanks for this nice and helpful tutorial.

  2. Montana Flynn

    January 26th, 2010 at 1:27 AM

    Thanks for going over CSS sprites, I used a similar technique today.

  3. Melvin José

    January 26th, 2010 at 4:57 AM

    Would love to see a detailed explenation of the “a.selected” technique.

  4. Gustavo Guichard

    January 26th, 2010 at 6:37 AM

    Unfortunately if you’re using PNG with background-positioning, it won’t be transparent on IE6. This is sad!

  5. Hunter Satterwhite

    January 26th, 2010 at 7:31 AM

    Really nice and simple.
    @Gustavo I’m sure a javascript PNG fix would let IE6 join the party with out a problem.

  6. Gustavo Guichard

    January 26th, 2010 at 8:32 AM

    @Hunter, Any suggestions?

  7. Hunter Satterwhite

    January 26th, 2010 at 9:17 AM

    @Guastavo sure thing! Andreas Eberhard has written a very nice jQuery plugin to fix png’s. He’s even included various instructions in the file heading on how to use it on document load and in noconflict mode.
    http://jquery.andreaseberhard.de/pngFix/index.html

  8. Zach Dunn

    January 26th, 2010 at 9:43 AM

    Thanks for the help Hunter!

  9. Vel

    January 26th, 2010 at 11:31 AM

    I’d add a.selected {cursor: pointer;} in css to make selected link to look like tab, and not link :)

  10. Gustavo Guichard

    January 26th, 2010 at 11:50 AM

    @Hunter, Thanks buddy!
    @Vel, I think it’s nice the way it is… Just thought

  11. güvercin

    January 26th, 2010 at 11:52 AM

    this is wonderfull example .. thanx gay!

  12. Saw Htoo

    January 26th, 2010 at 1:34 PM

    Thanks for the post. I have never used that technique before. Thanks! :)

  13. e11world

    January 26th, 2010 at 1:44 PM

    This is the first time I actually consider using this method just because you made it look so easy. I guess I also never bothered with it that much but your explanation and code is easy to understand. Thanks!

  14. BigM75

    January 26th, 2010 at 2:15 PM

    nice article, cool plugins

  15. Ardit Veliu

    January 26th, 2010 at 7:06 PM

    I use spriting for most of my projects but the way I originally learned it seems my CSS ends up a little bulkier than yours, going to have to look into that.
    p.s. My first time commenting here and the comment box is pretty awesome.

  16. Wayne

    January 26th, 2010 at 10:26 PM

    if you have fireworks it can do all the html/css/math for you with this cool plugin:

    http://www.andrewingram.net/articles/generating_sprite_navigation_from_fireworks/

  17. Hunter

    January 27th, 2010 at 12:28 AM

    @Vel nice idea! Now we should tie in some jQuery to make it fadein/out or ease some how to give it that little bit of “oomph” that people enjoy.

  18. Ward

    January 27th, 2010 at 7:46 AM

    Nice tutorial. Going to be using this a lot;)

  19. Webstandard-Blog

    January 27th, 2010 at 8:05 AM

    Nice posting Zach, but I’m not a friend of Sprites with text-content in it. You have to update the sprite-graphic every time your navigation is updated with new or changed “content”. If you develop multi-lingual projects, this kind of sprites aren’t the best solution.

  20. Hunter

    January 27th, 2010 at 8:36 AM

    @Webstandard-Blog good points, but is it really that much trouble to update a navigation bar with the way we do things today?

    If you’re worried about custom fitting text in different languages, than why not use something like sIFR to achieve the look and feel of the text and maybe expanding the sprite to include small, medium, and large size graphics to accommodate varied text sizes.

  21. Webstandard-Blog

    January 27th, 2010 at 8:41 AM

    @Hunter: Sprites are a good decision, thats not the question, but I would prefer a solution with just the “bottom-part” of the tabe images, rest of it made by text and css. So you aren’t addicted to the image or the language, if you know what I mean.

    By the way sIFR, would be a nice solution too and thx for your feedback!

    Greetings from Berlin ;o)

  22. Hunter

    January 27th, 2010 at 8:45 AM

    @Webstandard-blog oooooh yea just the “bottom-part”, now that just simplifies the whole process and combined with sIFR you’ve got a design easy to manage across different languages. It would even be great for using word as long as “Donaudampfschiffahrtsgesellschaftskapitän”. :)

  23. Ed Baxter

    January 27th, 2010 at 12:15 PM

    A great tutorial. I think if you can use them right sprites can help your site so much. My only concern is using text inside the graphic. I know that this is not an issue in terms of SEO due to the text-indent CSS however it can make things trickier if you have lots of sprites and need to keep opening Photoshop to change the text around.

    Great tutorial never the less!

  24. josekerekes

    January 28th, 2010 at 3:42 AM

    In case we want to use png images with alpha transparency in a sprite in ie6, we will encounter a problem.Using filter alphaImageloader is a solution to our problems but filter does not have background positioning.Fortunatelly the belatedPng script comes to our rescue, saving the day.It uses vml to handle png -s and yes it can handle background-positioning.If you are not bothered to use a script for fixing ie6 bug for suporting alpha transparency, or you don’t care about ie6 then everyting is allright.

  25. reza

    January 28th, 2010 at 7:00 AM

    i’ll use

    #menu li.home a:active{background-position:-5px -145px;}

    instead of

    #menu li.home a.selected{background-position:-5px -145px;}

  26. Benjamin Walsh

    January 28th, 2010 at 7:31 AM

    Anyone else notice that this isn’t working in ie8? Unless its on the fritz again.

  27. Webdesign Rosenheim

    January 28th, 2010 at 9:44 AM

    Grrreat tut!
    I’ll try this on the next webdesign project!
    Thanks for sharing!

  28. jitendra vyas

    January 28th, 2010 at 10:43 AM

    oh, nothing is showing if images is disabled. i usually surf with images disabled because i’ve very low internet conncetion and i keep images disabled in my mobile phones browser also to save bandwidth.

    It would be better if upon images disabled atleast simple hyperlink should be shown

  29. Tutorijali HDonWEB

    January 29th, 2010 at 2:36 PM

    Great css tutorial :-)

  30. Michael Szczepanski

    February 1st, 2010 at 4:02 PM

    Very simple and a great starting point. Thanks!

  31. Complain.O.matic

    February 2nd, 2010 at 1:18 PM

    I will be using this on my companies site when I do their redesign. As usual great tutorial.

  32. manidf

    February 3rd, 2010 at 7:34 AM

    nice one.

  33. zur4ik

    February 7th, 2010 at 4:58 AM

    nice :))

  34. Ezrad Lionel

    February 10th, 2010 at 8:49 AM

    In case anyone was wondering just how many sprites you could stick together, don’t bother trying with background-image. you’ll end up with a 2 second clip that bogs down your cpu. i have a method that gets infinite (depends on your pc ram) frames with virtually no cpu use. an example of a short sub 30 frame clip with dispersed frame interleaving for stress tests.

    http://novatvmedia.com/vved

    type v-v-e-d to see stats, try out in different browsers. and if you happen to try using your own tiles you’ll realize that yes indeed, internet explorer is shitting on the benchmark. notice also the sporadic nature of most rendering engines especially chrome.

  35. tuna

    February 11th, 2010 at 3:04 PM

    simple and nice, thanks..

  36. Nicole

    February 18th, 2010 at 2:41 AM

    Hi!

    thanks for that great tutorial. It was really easy to implement the css sprites (I finally understood how they work :)) and works like a charm.

    Nicole

  37. Mark James

    February 19th, 2010 at 4:56 AM

    Excellent tutorial, only just found out about this method! Will definately give it a go

  38. webdesign tom

    February 24th, 2010 at 7:08 AM

    wow, nice tut! thanks a lot, i’m going to use this technique! Does ist also work on my best friend IE?

  39. jakobsweg pilgern

    February 24th, 2010 at 8:07 AM

    thanks for this tut!
    sure, css sprite is the best way to implement hover effects!

  40. Hian Battiston

    March 5th, 2010 at 12:02 PM

    Simply an great tutorial! Thanks

  41. Onigiri

    March 9th, 2010 at 9:29 PM

    indeed a great tutorial, i was able to make my first ‘sprited menu’ thanks to it.
    I have a big question though: how would you add submenus to some of the menu items? I’ve been looking all over the net but can’t seem to find a solution…PLEASE HELP!!

  42. Zach Dunn

    March 11th, 2010 at 5:10 PM

    @Onigiri

    That’s far outside the specification of this tutorial. I recommend you create a secondary div which is replaced using jQuery based on which menu item is selected. Past that, I think you’d be best suited with a Google search.

  43. webseite erstellen

    April 7th, 2010 at 10:09 AM

    I studied the css tutorial and I really learned a lot. I think my next homepage will be a lot better than my first one.

  44. Rob

    April 21st, 2010 at 10:15 AM

    I suppose you could use the same principle to make seo friendly h2′s etc, would just mean a pain if you wanted to change the text in your CMS.

  45. Sas

    April 22nd, 2010 at 6:52 AM

    @Hunter: I have a page with CSS spites and jquery.pngFix.js doesn’t work properly unfortunately… It’s scaling all backgrounds and I see the whole sprite-image everywhere… :( …or I did any mistake?!

    Any suggestion?

  46. Juegos

    April 28th, 2010 at 12:40 PM

    You guys rock, very useful trick. Thank you.

  47. Barry

    May 28th, 2010 at 7:56 PM

    Great tut Zach. Just what I needed, nice+concise.

  48. wantfee

    June 11th, 2010 at 10:30 PM

    That is lovely. Thanks!

  49. Ryan Fitton

    July 1st, 2010 at 11:34 AM

    Hi i loved this tutorial but how could i make the menu center itself to my webpage but keep centered when i alter the width of the browser?

  50. Zeoplan

    July 24th, 2010 at 9:01 AM

    Thanks :)

Join the Conversation!

Remember: Life's not all doom and gloom, so please keep it constructive. If we've made an error or missed something big, please let us know! Learning is revisions, after all.

CommentLuv is Enabled

 

Sponsors

Advertise on Build Internet!