CSS Tabs

This tutorial outlines the creation of a tab module that uses only CSS; that means no images, and no JavaScript. You can skip ahead if you like - View Demo or Download. Update: I've updated this article to use CSS Target, check out the Advanced CSS Tabs.

In the not so distant past I was getting excited at the prospect of creating scalable, resizable tab modules that boasted shadows, gradients, reflections, and the like. This technique required the splicing of images, bulky JavaScript, and pretty much throwing semantics out the window – but hey, it worked.

In the past few years we’ve seen a huge leap forward in browser support for more complex CSS, which has nearly eliminated the use of these archaic techniques, and paved the road to a much cleaner, more scalable future.

I’m taking the progressive CSS we’ve seen a step further today, eliminating the images and JavaScript that are normally required for tabbing functionality, and showing how CSS can be used as a proxy for these bulky methods. This technique probably couldn’t be used successfully today, but shows how with a little innovation you can make CSS work wonders for you.

Clean HTML

<div id="tabs"a>
	<nav class="tabs"a>
		<a href="#"a>About Scamper</aa>
		<section class="tabs-content"a>
			Scamper is the coolest.
		<a href="#"a>His Anatomy</aa>
		<section class="tabs-content"a>
			Partly because he's a penguin.
		<a href="#"a>Life Achievements</aa>
		<section class="tabs-content"a>
			But also he had a movie made about him.
		<a href="#"a>More Info</aa>
		<section class="tabs-content"a>
			These tabs sure are great.

Waste not. We have our tabs container, the anchors for our tabs, and some content boxes that will toggle on hover as we roll over the tabs; so, so clean.

To accomplish this, we’ll need to absolutely position these boxes to visually appear below the tabs, even though in HTML they follow their controlling tab. Like so:

Beautiful CSS

Now we can flesh out the container and tab content. As described above, we’re going to position the tab-content containers to be at the bottom left of the main tabs container. This will allow us to use CSS to select them, and show the correct container as the mouse is rolled over a tab.

#tabs {
    border: 1px solid #DEDEDE;
    -webkit-border-radius: 4px;
    -moz-border-radius: 4px;
    border-radius: 4px;
    height: 205px;
    position: relative;
	overflow: hidden;
.tabs-content {
	padding: 25px;
	height: 120px;
	overflow: hidden;
	position: absolute;
	bottom: 0;
	left: 0;
	display: none;

Things start to take shape as we style the tab’s container with a simple gradient and border radius, topped with a box shadow at the top to give some lighting to the bar. Then some simple style is added to the tab, including some borders and text-shadow to increase depth.

.tabs {
	overflow: hidden; 
	background: #e1e1e1; 
	background: -moz-linear-gradient(center top , #f2f2f2, #e1e1e1); 
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f2f2f2), color-stop(100%,#e1e1e1)); 
	-moz-border-radius: 4px 4px 0 0; -webkit-border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0; 
	-webkit-box-shadow: 0 1px 0 #FFF inset; -moz-box-shadow: 0 1px 0 #FFF inset; 
	box-shadow: 0 1px 0 #FFF inset;
.tabs a {
	display: block; 
	float: left; 
	font: 15px/35px Arial, Helvetica, Sans-serif; 
	padding: 0 20px 0 40px; 
	color: #999; 
	text-shadow: 0 1px 0 #FFF;
	border-left: solid 1px rgba(0,0,0,0.05);
	border-right: solid 1px rgba(255,255,255,0.7);
	position: relative;
	overflow: hidden;

Now we’ll use a pseudo element for the circles with the :after class, and add the circles positioned within the tabs. This is the most complex element, but the breakdown is surprisingly simple. A gradient, some box shadows for lighting, border radius for it’s circular shape, and some nice positioning complete the element.

.tabs a:after {
	content: '?';
	position: absolute;
	top: 0;
	left: 10px;
	line-height: 21px;
	font-size: 10px;
	width: 21px; 
	text-align: center; 
	margin: 7px 10px 5px 0; 
	background: #000; 
	font-size: 12px; 
	-moz-border-radius: 21px; 
	-webkit-border-radius: 21px; 
	border-radius: 21px; 
	background: #bdbdbd; 
	background: -moz-linear-gradient(center top , #d4d4d4, #bdbdbd); 
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#d4d4d4), color-stop(100%,#bdbdbd)); 
	-webkit-box-shadow: 0 1px 0 0 #FFF, 0 1px 0 0 rgba(0,0,0,0.25) inset; 
	-moz-box-shadow: 0 1px 0 0 #FFF, 0 1px 0 0 rgba(0,0,0,0.25) inset; 
	box-shadow: 0 1px 0 0 #FFF, 0 1px 0 0 rgba(0,0,0,0.25) inset; 
	text-shadow: 0 1px 0 #999; 
	color: #ffffff;

Last we “code” the interactivity with the tab hover, which will change the tab background, circle color, and reveal the content associated with the tab. The first section adds a highlight color to the tab, then we display it’s correlating container, and add a hover to that container to make sure it doesn’t disappear if you mouse over it.

.tabs a:hover {
	background: #FFF;
	border-left-color: #CCC;
.tabs a:hover:after {
	background: #038bd5; 
	background: -moz-linear-gradient(center top , #2dc3fc, #038bd5); 
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#2dc3fc), color-stop(100%,#038bd5)); 
	text-shadow: 0 1px 0 #096c9e; 
	-webkit-box-shadow: 0 1px 0 0 rgba(255,255,255,0.45), 0 1px 0 0 rgba(0, 0, 0, 0.25) inset, 0 0 5px 0 rgba(0,148,255,0.85); 
	-moz-box-shadow: 0 1px 0 0 rgba(255,255,255,0.45), 0 1px 0 0 rgba(0, 0, 0, 0.25) inset, 0 0 5px 0 rgba(0,148,255,0.85); 
	box-shadow: 0 1px 0 0 rgba(255,255,255,0.45), 0 1px 0 0 rgba(0, 0, 0, 0.25) inset, 0 0 5px 0 rgba(0,148,255,0.85)
.tabs a:hover + .tabs-content {
	display: block;
.tabs a:first-child {
	border-left-width: 0;
.tabs a:last-child {
	border-right-width: 0;
.tabs-content:hover {
	display: block;

That’s it folks

To create this feature a few years ago would require a hefty amount of JavaScript (or a library if you’re not a pro), bulky images, and tons of added HTML. The total uncompressed size of this file is 4KB, blatantly, with the previous method you’d be in the hundreds. For practical use you'd want the content to be full-width, and make use of the :target selector, I choose this method because of the ideas it sparked in laying out HTML a specific way to work with dynamic css.

That’s it! Grab the code, view the demo, and share it! I’ve also opened comments for this article.

View DemoDownload

3 Responses to CSS Tabs

Leave a comment

  • You may use these HTML tags and attributes
    <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>