CSS-based tabs

There are many available solutions for creating a tabbed interface on a webpage. Most of them have in common that they are using JavaScript and/or use a html structure that separates the headers from the content that they belong to. What we aim to do here is to build a tabbed interface from a set of widgets, without changing the document structure. Let's start with some html code:

Our html code

<div class="widgets"> <div class="widget"> <h2 class="caption">Widget #1 caption #1</h2> <div class="content"> Widget #1 content </div> </div> <div class="widget"> <h2 class="caption">Widget #2 caption #1</h2> <div class="content"> Widget #2 content </div> </div> </div>

Now, this looks like a typical sidebar with one wiget below the other. We need to do a few things to build our tabbed interface.

  1. Take the content out of the document flow so the captions can flow naturally.
  2. Display the content of one widget at a time
  3. Highlight the caption for the active tab

To achieve this, we need a combination of absolute positioning and display: none; on the widgets. Display and caption highlighting will be triggered by hovering the widget.

Positioning the captions

Since the widget content is absolutely positioned out of the document flow, we can let the captions flow naturaly, one after another. I prefer to use float for this, it works consistently between browsers and do not add extra space like display: inline-block;. And clearing the following content is not an issue, we need a set height for the whole tab area anyway.

Displaying content from one widget at a time

We want to display content from one widget at a time, and the currently active widget is the one you are hovering. And as default, the first widget is active. The following code does that.

.widget:first-child .content { display: block; } .widgets:hover .widget .content { display: none; } .widgets:hover .widget:hover .content { display: block; }

The same technique will also be used for styling the caption for the active widget.


  • Preferably no space between the captions. Space will make the first widget appear as you move the mouse pointer between the captions.
  • There must be no space between the captions and the content because you will then lose the hover state on .widgets when you move the pointer from a caption to the content.
  • Fixed height on the widget content to avoid vertical jumping by the content below.
  • Limited number of tabs in horizontal configuration.
  • This approach does not work well on smaller screens. Consider fallback to a basic one-after-another layout when the screen becomes too small.

The catch

If you move the mouse pointer out of the tabs, the first tab will always be the visible one. You need javascript to fix that.

Complete example code for this post

Post a comment

You may use the following HTML:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>