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.
![]()
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.
![]()
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:
- Default is displayed to start
- Hover is activated by mouseover
- 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.



