HTML Dog

Skip to navigation

CSS Tabs

A popular form of navigation is tabbed navigation-a group of links that give the impression of being protrusions attached to different areas of unseen content. With CSS you don't need to be restricted to rigid images for every tab-you can maintain complete control over appearance and text at a fraction of the file size of image-only alternatives.

Tabs don't have to be horizontal but they usually are so our first step is going to be to create a horizontal list, as already explained above.

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


<div id="header"> 

<h1>Tabs</h1>
<ul>
	<li><a href="#">This</a></li>
	<li id="selected"><a href="#">That</a></li>
	<li><a href="#">The Other</a></li>
	<li><a href="#">Banana</a></li>
</ul>

</div>

<div id="content">
	<p>Ispum schmipsum.</p>
</div>

Basically, 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:


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

Now to get down to business...

Inline list-items

The first thing we can do is make the list horizontal with the most straight-forward solution-by setting the display property of the li elements to inline:


#header li {
	display: inline;
	border: solid;
	border-width: 1px 1px 0 1px;
	margin: 0 0.5em 0 0;
}

This rule set also starts to make the items a little more tab-like by applying a border to the top, right, and left sides. 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 elements a bit (adjusting this for the a element, rather than for the li elements, has the advantage of making the whole width of the tab clickable):


#header li a {
	padding: 0 1em;
}

So far the tabs aren't sitting on anything, so we should add a border to the content div:


#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:


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

This pads the bottom of the li element 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.

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 cannot 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 0.5em 0 0;
}

It's the same as before except that instead of displaying the li elements 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, to make IE stop larking about and miscalculating margins, we need to get rid of any margins above the list:


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

h1 {
	margin: 0;
	padding: 0 0 1em 0;
} 

Now things are 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:


#header #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 (#header #selected a) instead of the list item itself (#header #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.

And tabs don't have to have boxy 90-degree corners, either. One technique popularized by Doug Bowman is known as Sliding Doors, which involves two background images (one in the li element and one in the a element) for each side of the tab that slide over each other to accommodate different sizes.