Setting the current menu state with CSS

Every now and then I get an email from someone asking me how to use CSS to set the current state for a menu bar. Both the Inverted Sliding Doors tabs technique that I wrote about last summer and the navigation bar on this site, described in Turning a list into a navigation bar, use CSS to set the current state.

It isn't very complicated and has been described elsewhere, but to have somewhere to refer people asking about it I've written a quick explanation of how it works.

It's really quite simple, and I'll use this site as an example. There are a few main sections on the site: Home, About, Archive, Lab, Reviews, and Contact. These sections make up the top menu and are marked up as an unordered list, with each list item given a unique id:

  1. <ul>
  2. <li id="nav-home"><a href="/">Home</a></li>
  3. <li id="nav-about"><a href="/about/">About</a></li>
  4. <li id="nav-archive"><a href="/archive/">Archive</a></li>
  5. <li id="nav-lab"><a href="/lab/">Lab</a></li>
  6. <li id="nav-reviews"><a href="/reviews/">Reviews</a></li>
  7. <li id="nav-contact"><a href="/contact/">Contact</a></li>
  8. </ul>

The body of every document is then given an id that reflects which section it belongs in: <body id="home">, <body id="about">, <body id="archive">, <body id="lab">, <body id="reviews">, and <body id="contact">.

Note: if you look at the source of this site you'll find that I've used class instead of id. That's because the id is used for my CSS signature. It doesn't really matter which you use as long as you're consistent.

With the markup in place, you need to write one or more CSS rules to match the body id with the correct list item id. Again, using the navigation bar of this site as an example, the styles are applied to the links within the list items:

  1. #home #nav-home a,
  2. #about #nav-about a,
  3. #archive #nav-archive a,
  4. #lab #nav-lab a,
  5. #reviews #nav-reviews a,
  6. #contact #nav-contact a {
  7. /* declarations to style the current state */
  8. }

You may need an additional rule to style the :hover state of the current item. In this case the selectors would look like this:

  1. #home #nav-home a:hover,
  2. #about #nav-about a:hover,
  3. #archive #nav-archive a:hover,
  4. #lab #nav-lab a:hover,
  5. #reviews #nav-reviews a:hover,
  6. #contact #nav-contact a:hover {
  7. /* declarations to style the hover effect of the current state */
  8. }

That's all there is to it. The above rules only take effect when the body id matches that of a list item. Otherwise nothing happens.

This is a nice and simple trick that's useful when you can't use server side logic to insert a class or an id into the list item that holds the current menu item.

Posted on March 3, 2005 in CSS