Last tutorial, I showed you how to design a watercolor effect menu in Photoshop. This tutorial I will show you how to slice up the menu design (step by step) and put them together with CSS. Most of you probably know how to code a horizontal or vertical CSS list menu. Now let's take it to the next level — code an advanced (un-typical) list menu utilizing the CSS position property.
Overview
Here are the required graphics to assembe the menu (you can download from the zip).

1. Main background
Open the Photoshop file. Turn off the menu text Layer Group and save the main background as menu-bg.jpg.

2. Button graphics
Turn off the background Layer Group and leave only the menu text layers visible. Make a rectangle selection cover the "home" item, go to menu Edit > Copy Merged (Cmd + Shift + C).

Create a new file and take note of the file dimension (w x h), in my case the "home" graphic is 144 x 58px. Paste the "home" graphic in the new file. Go to menu Image > Canvas Size, adjust the image height x 2 (58 + 58 = 116px). Duplicate the home graphic layer and align it to the bottom. Erase the highlight strokes in the upper layer.

Here is how the hover effect will work. We will set the link button to 144 x 58px, when mouseover, we will shift the background image from top to bottom.

Repeat this step for the other buttons. You should have the follow graphics:

3. HTML source
When you are done with the graphics, let's start coding. Start with an un-ordered list <ul>.
- note there is an id="menu" assigned to the
<ul>tag - an unique class name assigned to each link
<a> - an empty
<span>tag (the purpose of this is to make the mouseover effect)
<ul id="menu">
<li><a href="#" class="home">Home <span></span></a></li>
<li><a href="#" class="about">About <span></span></a></li>
<li><a href="#" class="rss">RSS <span></span></a></li>
</ul>
#menu
Reset the menu to no padding, no margin, and no list-style. Specify the width and height same dimension as the menu-bg.jpg. Then attach the menu background image. The key point to remember here is set the position property to relative.
#menu {
list-style: none;
padding: 0;
margin: 0;
width: 774px;
height: 210px;
background: url(images/menu-bg.jpg) no-repeat;
position: relative;
}
#menu span
Specify the span element to display:none (so they will be invisible by default). Specify position:absolute, so we can place the mouseover GIF image on exact position.
#menu span {
display: none;
position: absolute;
}
#menu a
The key point here is the text-indent property. We specify the text-indent property with a negative value (-900%), so the text will be hidden.
#menu a {
display: block;
text-indent: -900%;
position: absolute;
outline: none;
}
#menu a:hover
When mouseover the link, we want to shift the background image from top to bottom.
#menu a:hover {
background-position: left bottom;
}
#menu a:hover span
When mouseover the link, we want the span element to display:block.
#menu a:hover span {
display: block;
}
#menu .home
Specify the width, height, and background image. Since we already specified all <a> element postition:absolute in previous step, now just say where the .home button should be by specifying the left and top property.
#menu .home {
width: 144px;
height: 58px;
background: url(images/home.gif) no-repeat;
left: 96px;
top: 73px;
}
#menu .home span
Here we are specifying the width, height, background, and position of the span element of .home (mouseover GIF image)
#menu .home span {
width: 86px;
height: 14px;
background: url(images/home-over.gif) no-repeat;
left: 28px;
top: -20px;
}
#menu .about
Copy the .home rules and rename them to .about. Now just change the width, height, background, left, and top property.
#menu .about {
width: 131px;
height: 51px;
background: url(images/about.gif) no-repeat;
left: 338px;
top: 97px;
}
#menu .about span {
width: 40px;
height: 12px;
background: url(images/about-over.gif) no-repeat;
left: 44px;
top: 54px;
}
#menu .rss
Repeat this step for .rss
#menu .rss {
width: 112px;
height: 47px;
background: url(images/rss.gif) no-repeat;
left: 588px;
top: 94px;
}
#menu .rss span {
width: 92px;
height: 20px;
background: url(images/rss-over.gif) no-repeat;
left: 26px;
top: -20px;
}
All in one:
#menu {
list-style: none;
padding: 0;
margin: 0;
width: 774px;
height: 210px;
background: url(images/menu-bg.jpg) no-repeat;
position: relative;
}
#menu span {
display: none;
position: absolute;
}
#menu a {
display: block;
text-indent: -900%;
position: absolute;
outline: none;
}
#menu a:hover {
background-position: left bottom;
}
#menu a:hover span {
display: block;
}
#menu .home {
width: 144px;
height: 58px;
background: url(images/home.gif) no-repeat;
left: 96px;
top: 73px;
}
#menu .home span {
width: 86px;
height: 14px;
background: url(images/home-over.gif) no-repeat;
left: 28px;
top: -20px;
}
#menu .about {
width: 131px;
height: 51px;
background: url(images/about.gif) no-repeat;
left: 338px;
top: 97px;
}
#menu .about span {
width: 40px;
height: 12px;
background: url(images/about-over.gif) no-repeat;
left: 44px;
top: 54px;
}
#menu .rss {
width: 112px;
height: 47px;
background: url(images/rss.gif) no-repeat;
left: 588px;
top: 94px;
}
#menu .rss span {
width: 92px;
height: 20px;
background: url(images/rss-over.gif) no-repeat;
left: 26px;
top: -20px;
}
Done
That's it. You can preview my CSS menu.
Note: there is an IE6 bug where the <span> hover effect doesn't display properly. To fix that, you can use Javascript to specify the <span> to display block on mouseover.
Great you have this tip continued and put it to the next level.. a Must Read tutorials indeed.. Bravo again!
nice tutorial, but using 7 images here seems a bit bulky when it could be done with 2. check out elliot’s tutorial above or alistaprt for the css sprite method.
@Mike – Yes, alternatively you can put all the button graphics in one single GIF image, but by separating the graphics it gives better control. I can simply change the button location by the top and left property (without going to Photoshop, editing the image, and then changing the CSS again).
@Jonny Haynes, Paul Wilkins – Thank you for the correction. The typo is fixed (changed from <ol> to <ul>).
nice one… i was waiting for such a tutorial….
actually i wanted to implement a horizontal navigation menu in a wordpress theme, where normal and hover states are different images. This tutorial is a bit close to that, but can u please help me out and let me know how can i achieve such menu in wordpress?
what function does the “outline:none” on the “#menu a” element have?
@andrej – the outline property is to remove the dotted border around the link in Firefox on click.
thank you, nick. great article by the way.
I was wondering if there is any negative search engine outcome when using css-properties such as text-indent: -900% to remove search engine relevant html code from the users eye.
In your case it is not critical, however what about properties like display:none, are capable of removing whole blocks of text.
Wow. Exelent man, as always. You’re like my heroe, every day i learn more and more XHTML tips but this is just great.
@Nick: Yes, it can be done in two images.Why seven? It’s because of the amount of time consumed when loading the whole image needed for the sprites?
@ andrej: As far as I’ve found, there are no negative search engine outcomes to using a negative margin on the text – the text is still in the markup and is fully readable by search engines and screenreaders. On the other hand, some search engine robots and screenreaders ignore any text that’s hidden by display:none (or so I’ve read) so that would have an impact. Both methods fall down when images are turned off and CSS is turned on in a user’s browser, but there are a couple of ways around this (which require non-semantic span tags, unfortunately) – mezzoblue has a list of different methods with advantages and pitfalls.
For most sites I design/build, I use a semantic single-image negative margin method with the background image, display:block and dimensions applied directly to the ‘a’ tag. It’s served me well so far, and it’s reasonably quick to do.
@Mike: Search engines discourage what they call cloaking, basically intentionally showing the search engine something different than what your site shows a user. Sites that use a heavy amount of Flash often cloak to get their site content in the search engines. I do not think negative margin would be considered cloaking.
Search Engine Spiders cannot read CSS or JS so I doubt that they are paying attention to whether or not an element is set to: display:none or visibility:hidden.
Just turn off your CSS in FF and that is most likely what Google sees.
Rollovers in css basically right? Nice effect, the notepaper effect is still pretty fresh.
There is a better method, although it takes a bit extra CSS code, that only requires the use of one image. By using only one image for all effects (normal, focus, hover, etc..), you are guaranteed that all images will be displayed instantly without any extra loading time when hovered over or focused on.
To do this, you use the “background-position” property.
Quite a nifty little trick which I use on most of my designs nowadays.
Very nice indeed.. I love the whole freestyle feel to it. It doesn’t feel so, bland. Cool idea.
Hmmm. If you’re going to use images for just about everything in the menu, why are you even bothering with CSS? One of the chief advantages of CSS menus is that they’re easy to update — they’re text. With this menu, you have to redo images and worry about sizes every time something changes. It’s a beautifully done menu, but still.
Overall very nice. Doctype on this is XHTML 1.0 Strict when it should be Transitional. The empty <span> tag is throwing validation warnings as well as the <link> tag inside of the <div id=”content”>. The single image is great but the use of the empty span can be overcome as you mentioned with the negative margin.
Well done, thanks.
How in the !#@$$ is this advanced? its @#$% css…
wow — so, so simple yet so genius — tnx for the tips.
amazing!! your blog is great and this tutorial rocks!!
Cheers!
Well, ryan, it’s !#@$$ advanced CSS because there are other, simpler, methods of using CSS for menus. I’m sorry this article insulted your supreme intelligence and skill.