No silly javascript, no crazy coding, no waiting for images to load. Just some good old fashioned HTML, CSS, and a single image. Once you do this, you’ll never make your web site navigation any other way.
Warning: If you aren’t into front-end coding for the web, you may want to skip this. For those that are (I love you that much more), this has been covered elsewhere and covered much better, so hopefully this is old hat.
Can’t wait for the results? Here’s the final navigation with CSS image replacement, used in the real world. Please, disable styles, view source.
How to do it
First, you should already be in the habit of making your navigation using unordered lists. If you’re not doing it, now is the time to start.
Setup your navigation in an unordered list:
<ul> <li><a href="#">Navigation item 1</a></li> <li><a href="#">Navigation item 2</a></li></ul>Next, add a little CSS to control your list items:
ul li { display:block; float:left; list-style-type:none; }Such basic CSS results in:
With a few margin and font adjustments, you could stop here and you’d have yourself a nice clean navigation. But only nerds (and search engines) like such bland, basic, HTML navigation. We’re here to please our designers and clients. So Let’s turn this basic HTML into something so sexy they’ll shed tears at first sight. Something that will look like this:

“Oh, and can you make it kind of POP on hover?”
Why yes; in fact we can.
Make yourself an image that contains both the :link state and :hover state of all your navigation items. Better yet, teach your graphic designer to do this for you. In the example below, the :link states are on top and their :hover directly below. Both areas must be the same height.
Here’s what the image looks like, with some guides:

You’ll then export that file and use it as a background-image for all of the links in your unordered list. Here’s where your guides come in handy. In this example, the link area has a height of 66 pixels and the first list item is 34 pixels wide, so we’ll setup some CSS defaults for the anchor tags:
ul li a { display:block; height:66px; width:34px; background:transparent url(navigation.png) no-repeat 0 0; text-indent:-9009px; }You’ll notice the text-indent:-9009px; That pulls the text out of sight and out of mind. Make way for your pixel princess!
My second list item is wider, so let’s give that one an ID and change the width. We also need to pull the background-image 34 pixels to the left, since that’s where the image for the second list item starts.
<ul> <li><a href="#">Navigation item 1</a></li> <li id="navigation2"><a href="#">Navigation item 2</a></li></ul>ul li#navigation2 a { width:60px; background-position: -34px 0; }Now our regular old HTML unordered list is starting to get somewhere:

Now for the :hover & the real magic
All that’s left is to move the background-image on :hover. Since our list items have a height of 66 pixels, we’ll move the background-image up 66 pixels for each list item:
ul li a:hover { background-position: 0 -66px; }ul li#navigation2 a:hover { background-position: -34px -66px; }You’ll now have the start of one sweet ass, simple navigation:
Throw some margins in there for spacing, or add whatever tweaks you deem necessary. The final step is to laugh at how simple this is, and never look back.
Carry this same process throughout the rest of your navigation and you’ll end up with something so search engine friendly you’ll now be crying along with your client.
Here’s the final navigation with CSS image replacement, used in the real world. Please, disable styles, view source. If you look carefully, you’ll notice that once the client asks you to change the order of the list items, it’s as simple as moving around your LI’s in the HTML into any order you’d like.
If you have improvements, ways to make this more efficient, or you’d just like to share how long you’ve been using this technique for and how old it is; Please, leave your comments.
Update:
To get your hover state to stay in the hover state, to mark the users currently selected page for example, I like to use an ID or class on the body tag.
For example, on a contact page add:
<body id="contact">And in your CSS hover state, add a line for body#contact:
ul li a:hover,body#contact ul li a { background-position: 0 -66px; }Did you find this post helpful?
Mike Tomasello #
Used the same technique on a site I made a few weeks ago.
I did though, begin to wonder if it would be easier to have each as an individual image rather than one big image for all (so that background-position changes could be applied to all [the x values would be 0 for all]).
When you have say 7 menu items each with a different standard image, a :hover, :active, :focus, and selected page, the CSS background-positions start to add up.
j bird #
hahahah!
that was easy. heard about it about a month ago. But this is the first place that described how it works. Thanks.
Bill #
Even apple uses a single image!
Kristof Gheyssens #
I’ve followed your instructions, image replacements works nicely, BUT my navigation div is 800px as is the sum of all my ’s, as you can see (http://www.puregraphx.be/security) the last list item is thrown to the next line. Please help!
Thanx
Mark #
WOW! Works like a dream as you said!
BUT… How do you get a image to stay like the hover state. If your in that section. so the navigation button stays highlighted. like apple :o)
I have tried creating a style with a different name which I change on each section to say highlight this.. with the same styles as the a:hover but it doesn’t work??
might be a good addition to this code?
Thanks
Bill #
Mark - What you need to do, is on each of your sites pages, add an ID or class to your body tag.
For example, on a contact page add:
body id=”contact”
& in your CSS hover state, add a line for body#contact:
ul li a:hover,
body#contact ul li a {background-position:xxx;}
Make sense?
PhiL #
Thanks for this tutorial! Works perfectly!!
PhiL
PhreQuencYViii #
This is awesome! But my question is, how would you center a navbar like this? I have one made, but I can’t get it to center on the top.
Bill #
Phrequencyviii - you would center the entire UL, perhaps by putting it in a block that has text-align: center in it, and setting your UL to have right & left auto margins with a set width.
Something along these lines:
div.nav-wrapper {text align: center;}
ul {width: 200px; margin: 0 auto;}
KBG #
Thank you so much. Camxso
Deena #
I knew this was possible but I could never get it right. Thanks for explaining it so well!
Chet #
Thanks dude, exactly what I was looking for!
Jeff #
I’m trying to convince my designer that this technique is better than having a bunch of smaller images. Thanks for the explanation.
craig #
hello, im building my first web site and was trying to accomplish this example on image roll overs but it didn’t seem to work and i’ve been trying everything, is there some catch im missing#???
craig #
scrap that, works now but every time i try to center it on my page it doesn’t center it properly beacuse of the li dot to the left of the image, any ideas???
JP #
Brilliant and simple–thanks so much!
Josh #
I had a problem when i wrapped my UL list inside a div tag it was being pushed away from the edges. I added little css to the UL and it solved my problem.
-----------------------
#nav{
margin:0px;
padding:0px;
}
ingilizce #
CSS “Cascading Style Sheets” Lessons
css list style Properties and examples — http://css-lessons.ucoz.com/list-css-examples.htm
Bradfields #
Awesome post, been pissing about trying to get a nav to work all morning, read this and it was sorted within 5 minutes.
Much respect to you sir!!
Richard J Keys #
This was one of the first things I learned in “the real world” after leaving university.
Excellent tutorial, especially the comment about adding an id to the body of each page - sure beats my messy solution! :p
ian #
Hi, Thanks for the walk through. I have managed to surprise myself! I have one problem though. On your update you show how to set a image to be “on” when the user is on the page. I cannot get this to work. When I apply this to the hover code and set the body id, all, the images get set to the same thing! I hope this makes sense and you could point me in the right direction. Thanks very much. Ian
joe #
dude, brilliant.
Tison #
Thanks for the article - not only is this a great CSS Image Replacement tut, but a solid CSS mouseover tutorial as well. Gave you some trackback love, Thanks again
Nippy #
Many thanks for sharing this, just what I was looking for.
Jenn #
This is an awesome tutorial…it was the best one I found online so far. Any ideas on how to implement this technique in dreamweaver using PHP? All the sites I’ve found have not been helpful as they all use multiple images and spans to achieve this affect and the php code is written for that instance.
Bill Keller #
Jenn While I don’t use Dreamweaver, its certainly possible to use any tool to output what you’ve done here. Good luck & thanks!
Luiz Lopes #
This is great, just what I was looking for.
Thank you for sharing it.
Marty #
Hi Bill.
I’m having two css image navigations on one page. Is there any tips you can give for having two buttons in two different navigations stay in rollover state?
Bill Keller #
Marty - Use a unique class on your second navigation and select with CSS accordingly.
John #
I’m having the same problem a Kristov - and the question was never answered.. please help…I’ve followed your instructions, image replacements works nicely, BUT when i put the ul’s in a containing div that is the same width as the nav bar itself it forces the last image down below the rest. Any ideas?
Thanx
Bill Keller #
John - It sounds like your UL is actually wider than the containing div. I recommend resetting margins and paddings to zero on all items first, using * {margin: 0; padding: 0;}
anna #
Hey there.
I’m having the same issue as ian. I have 4 pages and when I use the IDs for each to keep the hover state on the current page it places it at the first link. Another words, I can’t seem to change the location of the second, third, or fourth link. They all show up on top of the first link. Solution?
Thanks!
Bill Keller #
Anna - Are you adding a unique ID to the body of each HTML page? And then adding the appropriate CSS?
For example:
body#navigation2 ul li#navigation2 a {}
kaye #
do you know that i love you? i am much closer to opening our e-store because of this.