HTML Dog
Skip to navigation

CSS Tabs

Wikipedia, eBay, ask.com, PayPal, and a squillion other sites: a popular form of navigation design is tabbed navigation — a group of links that give the impression of being protrusions, attached to different areas of unseen content.

Tabbed navigation made from list items and dollops of CSS

Tabs don’t have to be horizontal but they usually are so our first step is going to be to create a horizontal list.

We’re going to try a few different things with CSS, but we’ll be sticking with the following basic HTML structure:


<header> 

<h1>Tabs</h1>
<nav>
    <ul>
        <li><a href="this.html">This</a></li>
        <li id="selected"><a href="that.html">That</a></li>
        <li><a href="theOther.html">The Other</a></li>
        <li><a href="banana.html">Banana</a></li>
    </ul>
</nav>

</header>

<section id="content">
    <p><!-- Big lovely oodles of content --></p>
<section>

Now, what we want to do with this HTML is turn each list item into a tab, with the selected item appearing to be part of the corresponding content area.

First of all, we can rip out the list item markers and zero the margin and padding of the ul element:


nav ul {
    list-style: none;
    padding: 0;
    margin: 0;
}

Now to get down to business…

Inline list-items

The most obvious first thing we can do is make the list horizontal. The most straight-forward solution for this is to set the display property of the boxes created by the li elements to inline:


nav li {
    display: inline;
    border: solid;
    border-width: 1px 1px 0 1px;
    margin: 0 5px 0 0;
}

This rule set also starts to make the items a little more tab-like by applying a border to every side except the bottom. The margin property here zeroes the margin on all sides except the right, because we’re going to space the tabs out a bit.

Now we can make things a little tidier by padding out the a element boxes.


nav li a {
    padding: 0 10px;
}

So far the tabs aren’t sitting on anything so we can add a border to the content section:


#content {
    border: 1px solid;
}

But there’s one essential thing missing. As it is, the tabs are just sitting across the top of the content box, all looking pretty much the same. What we need to do is make the “active” tab — the one that relates to the page we’re on — look as if it’s part of the content box, like a tab on the side of a dividing card.

Because vertical padding in inline boxes doesn’t actually push anything out around it, we can simply do this:


#selected {
    padding-bottom: 1px; 
    background: white;
}

This pads the bottom of the li element box with the “selected” ID by one pixel, which pushes it over the top border of the content box. As the background color is white (assuming the content box’s background color is also white) it gives the illusion that the tab, and its border, are part of the content box.

Simple tabs using display: inline

Floated list-items

So far, this technique is great for basic tabs. Colors, border colors, text decoration, etc. can all be changed to suit. When it comes to padding, though, things go awry. For the very same reason that the “selected” tab works by spilling over onto the content box, padding can’t be applied to the initial tab states. They just wouldn’t behave.

So if we want to do something a little funkier with the tabs, we need to horizontalize the list items a different way:


#header li {
    float: left;
    border: 1px solid;
    border-bottom-width: 0;
    margin: 0 5px 0 0;
}

It’s the same as before except that instead of displaying the li element boxes inline, we are floating them to the left.

Doing this breaks a few things elsewhere, so before we can continue we need to clear the content box from the float’s evil grasp and then we need to get rid of any margins above the list:


#content {
    border: 1px solid;
    clear: both;
}

h1 {
    margin: 0;
    padding: 0 0 10px 0;
}

We’re almost there with this method but instead of applying padding to the selected list item like we did with the inline list item approach (which here would just pad things out because a floated box has a “block” display type), we are going to lift the whole thing and smack it down one pixel:


#selected {
    position: relative;
    top: 1px;
    background: white;
}

So now things look almost the same as they did with the inline method. One little difference is that the selected tab is one pixel lower than the others because it has been pushed down to cover the bottom line. To avoid this you can apply the last declaration block with the positioning and the background color to the link inside the list item (#selected a) instead of the list item itself (#selected), which can achieve a more desirable effect.

Making things look nicer…

There are little things we can do to make these tabs look better such as removing the underlines, providing different colors for borders, changing the background colors when hovering etc, which can make the tabs more discernable and the “active” tab more obvious.

Playing around

Of course, tabs don’t have to be as borderific as the above examples. The main principles stay the same — you set your horizontal list items and then style them how you please.

You can just separate tabs by using solid background colors. Alternatively, a simple trick, conjured up by Dan Cederholm is to manipulate the bottom border of a list item to produce thin protruding tabs.

Skinny tabs

And tabs don’t have to have boxy 90-degree corners, either. Applying border-radius to the top left and top right corners of each tab will make them all the more like those dividing cards we so want to emulate.