Horizontal Menu 101

I know this is nothing new, but I was surprised the other day when a friend asked me if there was a jQuery plugin I used to create this effect.

Here is the idea: Turn this

1
2
3
4
5
6
7
<ul id="nav">
  <li id="nav_home"><a href="" title="Home">Home</a></li>
  <li id="nav_about"><a href="" title="About">About</a></li>
  <li id="nav_clients"><a href="" title="Clients">Clients</a></li>
  <li id="nav_portfolio"><a href="" title="Portfolio">Portfolio</a></li>
  <li id="nav_contact"><a href="" title="Contact">Contact</a></li>
</ul>

into this

complete

First of all, if you haven’t read “CSS Design: Taming Lists” then start there – and welcome to the internet, you must be new here?

The basic idea is to keep the HTML meaningful, clean, portable and flexible. We do this by not complicating the HTML with things that don’t make sense apart from the design.

To accomplish this, a little CSS will go a long way.

First we need to get this unordered list to display in a horizontal row. While we’re at it we’ll put some other parameters around the UL to help guide us along the way.

1
2
#nav{width:576px; height:40px; list-style-type:none;}
#nav li{display:inline;}

All we’ve done so far is tell the UL with the ID of nav to have a width, height and that there shouldn’t be any bullets on the list items. Then we told the li that belong to #nav to display inline – horizontal.

The next step is where the real work is. We’re going to tell the anchor tags to look and behave like graphical buttons – when in reality, they are still just some simple HTML and text.

We do this by making each of the anchor tags a block element. Once we do that, our new block elements are going to want to stack on top of eachother – so we float the left. We also know that each menu item shares a common height, so we declare it here to save ourselves the need to repeat the height for each anchor tag. Lastly, we need to send that text packing because we want to use a graphical representation for the text. To do that, indent the text way, way, way off the page.

1
#nav li a{display:block; float:left; height:40px; text-indent:-9999px;}

If you look at what your browser sees, you shouldn’t see anything. Don’t worry though, we’ll bring it all back quickly.

To get the graphical image in place of the text we’re going to make a little PNG sprite that contains 3 instances of what the button could be. This will make sense in a minute, but this is what we’re working with:

40px

The idea here is that we only display a portion of the image for each anchor. We already declared in our CSS that our anchor tags should be 40px tall, which means we’re only displaying 1/3 of the image at a time, and then manipulate the position of this image based on interaction.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#nav li a:hover{background-position:center center;}
 
#nav_home a{width:112px; background:url(images/nav_home.png);}
.home #nav_home a{background-position:center bottom;}
 
#nav_about a{width:110px; background:url(images/nav_about.png);}
.about #nav_about a{background-position:center bottom;}
 
#nav_clients a{width:109px; background:url(images/nav_clients.png);}
.clients #nav_clients a{background-position:center bottom;}
 
#nav_portfolio a{width:126px; background:url(images/nav_portfolio.png);}
.portfolio #nav_portfolio a{background-position:center bottom;}
 
#nav_contact a{width:119px; background:url(images/nav_contact.png);}
.contact #nav_contact a{background-position:center bottom;}

I’ve split each menu item into a block of CSS for easy digesting, but they are basically all the same. We define a width, which is specific to the actual width of the image, and then we use CSS to bring that image in as a background. Once we’ve done that, we add a pseudo-class :hover to each anchor to adjust the position of the background. Simple huh?

Lastly, I added a little CSS hook to change the background position based on which section of the site the user is in. To make this work for you, all you need to do is address something that changes in your CSS based on section. A simple way to do this would be to add a class to the BODY tag that corresponds with the section name. In this case, I’ve added .home to the BODY tag while declaring that my #nav_about anchor should use the background property of center bottom.

Working Example

Reasons for implementing your visuals this way:

  1. Keeps your markup clean and portable
  2. Decreases load time for images – you’re only loading one
  3. No flickering when the image is being “replaced” – it’s already loaded
  4. Most importantly, you won’t look like a noob!

Other Resources

If you’ve found this helpful, pass it around. Comments are welcome!

No related posts.

This entry was posted in Design and tagged , , . Bookmark the permalink. Both comments and trackbacks are currently closed.

2 Comments

  1. Posted April 22, 2009 at 2:05 pm | Permalink

    Very cool man! I am going to be making a website fro my self soon, I’m sure this will come in handy!!

  2. admin
    Posted April 23, 2009 at 6:36 am | Permalink

    Feel free to snatch any of the images/css/html for reference Willis! Enjoy!