CSS Overlapping Tabbed Navigation Using Z-Index and Relative Positioning

by Matt on March 30th, 2009

In this tutorial I will demonstrate how to create a layered tab navigation (hover your mouse over the tabs):

To accomplish this, you can use a combination of a PNG image with alpha-transparency and CSS, using the z-index and position properties.

Please note: because the code uses a PNG with alpha-transparency and background-image positioning rules, this demo does not work for IE versions 6.0 and below. However, the demonstration of the CSS rules used to layer tabs is valuable information, and you will find it useful in your quest to create a layered navigation.

1. Setting up our horizontal navigation

This navigation follows three basic rules:

  1. The list items float left
  2. The anchor tag inside each list item fills the entire tab
  3. The anchor’s background images are PNGs with transparency

To fulfill rule #3, here’s a nice sprite for our background-imaged tabs; from top to bottom, they are the active tab, hover tab, and default tab:

nav_bgs

Remember: The images, or combination of images like I’ve used above, must have transparent “edges” – in this case, the “whitespace” beyond the curved areas of the tabs.

The HTML:

<ul id="demo_navigation">
     <li><a href="/">Home</a></li>
     <li class="active"><a href="/products.php">Products</a></li>
     <li><a href="/support.php">Support</a></li>
     <li><a href="/contact.php">Contact</a></li>
     <li><a href="/about.php">About</a></li>
</ul>

And CSS:

#demo_navigation { list-style-type: none; }
#demo_navigation li { float: left; }
#demo_navigation li a {
     display: block;
     width: 132px;
     line-height: 31px;
     text-align: center;
     color: #000;
     background: transparent url('/wp-content/uploads/2009/03/product_nav_li_bgs.png')
          bottom left no-repeat;
}
#demo_navigation li a:hover {
     text-decoration: none;
     background: transparent url('/wp-content/uploads/2009/03/product_nav_li_bgs.png')
          0px -31px no-repeat;
}
#demo_navigation li.active a {
     color: #fff;
     background: transparent url('/wp-content/uploads/2009/03/product_nav_li_bgs.png')
          0 0 no-repeat;
}

Result:

2. Shift your tabs over with position: relative

When you set an element to have the property “position: relative;” you are setting up the element to be moved relative to where it is originally positioned. Moving an element from where it is originally implies the use of the top, right, bottom and left properties. So for example, you have this box:

[]

To move it +15 pixels from its original left position you set the position and left properties as such:

#box {
     position: relative;
     left: 15px;
}

And where is that box now?

   []

So perhaps you can begin to see, if we want layered tabs, we simply have to shift tab 2, 3, 4 and 5 negatively left from their original positions. Remember though, for each tab you shift over, that means you have to accommodate for that shift in the next tab you move over.

  • If the first tab shifts 8 pixels left…
  • The second tab will shift 16 pixels left
  • Third tab shifts 24 pixels
  • etc etc

These distinct rules for each tab require us to create IDs for each list item. The updated HTML (updates in bold):

<ul id="demo_navigation">
     <li id="demo_nav_home"><a href="/">Home</a></li>
     <li id="demo_nav_prod" class="active"><a href="/products.php">Products</a></li>
     <li id="demo_nav_support"><a href="/support.php">Support</a></li>
     <li id="demo_nav_contact"><a href="/contact.php">Contact</a></li>
     <li id="demo_nav_about"><a href="/about.php">About</a></li>
</ul>

And the CSS, now with relative positioning:

#demo_navigation { list-style-type: none; }
#demo_navigation li {
     float: left;
     position: relative;
}
#demo_navigation li a {
     display: block;
     width: 132px;
     line-height: 31px;
     text-align: center;
     color: #000;
     background: transparent url('/wp-content/uploads/2009/03/product_nav_li_bgs.png')
          bottom left no-repeat;
}
#demo_navigation li a:hover {
     text-decoration: none;
     background: transparent url('/wp-content/uploads/2009/03/product_nav_li_bgs.png')
          0px -31px no-repeat;
}
#demo_navigation li.active a {
     color: #fff;
     background: transparent url('/wp-content/uploads/2009/03/product_nav_li_bgs.png')
          0 0 no-repeat;
}

#demo_nav_prod { left: -12px; }
#demo_nav_support { left: -24px; }
#demo_nav_contact { left: -36px; }
#demo_nav_about { left: -48px; }

Result:

3. Polishing with z-index

Now we have this great layered navigation, but the tabs perhaps aren’t layered in the most intuitive fashion. For instance, we’ll probably want the active tab to be on top of them all, and we may want the default layering scheme to be descending left-to-right, so Home is atop all the rest, and About is on the bottom.

Here’s where z-indexing comes into play.

The z-index property “sets the stack order of an element. An element with greater stack order is always in front of another element with lower stack order.” So, if we want the Contact link to be above About, then we set Contact’s z-index to 1 (z-index: 1). Then, if we want Support above Contact, we set Support’s z-index to 2. So on and so forth… until we decide that we want the active tab, no matter which it is, to be above the rest. So we count the number of tabs, and set the active tab (as referenced by “.active”) to have a z-index: tab_count;

In this case, we have 5 navigation elements, so we would set the z-index of the .active element to 5. Now, our updated and final CSS:

#demo_navigation { list-style-type: none; }
#demo_navigation li {
     float: left;
     position: relative;
}
#demo_navigation li a {
     display: block;
     width: 132px;
     line-height: 31px;
     text-align: center;
     color: #000;
     background: transparent url('/wp-content/uploads/2009/03/product_nav_li_bgs.png')
            bottom left no-repeat;
}
#demo_navigation li a:hover {
     text-decoration: none;
     background: transparent url('/wp-content/uploads/2009/03/product_nav_li_bgs.png')
            0px -31px no-repeat;
}
#demo_navigation li.active a {
     color: #fff;
     background: transparent url('/wp-content/uploads/2009/03/product_nav_li_bgs.png')
            0 0 no-repeat;
}

#demo_navigation li.active { z-index: 5; }

#demo_nav_home { z-index: 4; }
#demo_nav_prod { left: -12px; z-index: 3; }
#demo_nav_support { left: -24px; z-index: 2; }
#demo_nav_contact { left: -36px; z-index: 1; }
#demo_nav_about { left: -48px; z-index: 0; }

And here is the final product, in all its layered glory:

2 Comments
  1. Hi. Very very helpful. I did a site for http://www.katyestradacpa.com and I wanted to do something like this in case I needed to add a tab and didn’t want to re-size my graphics. Thank you thank you.

  2. If you use “margin-right: -12px;” in addition to the “left: -12px” css-attribute you wouldn’t end up adding a special css-class/id for every menu point since all the points would only need to be shifted 12pixels on their own effort :)

Leave a Reply

Note: XHTML is allowed. Your email address will never be published.

Subscribe to this comment feed via RSS