Animated Content Tabs with CSS3

In this tutorial we are going to implement some simple CSS3 content tabs using radio buttons together with the :checked pseudo-class and sibling combinators.
CSS3 Content Tabs

From our sponsor: Looking for an intuitive whiteboard style project management tool? Give Shortcut a try for free.

CSS3 Content Tabs

Content tabs are a very common and familiar element in web design, and often their turn out to be pretty useful. So, in this tutorial we are going to implement some simple CSS3 content tabs using radio buttons together with the :checked pseudo-class and sibling combinators.

Note that the CSS3 properties will only work in browsers that support them.

The Markup

We will be using input elements to connect to the division with the class content. The content division includes all of the “tab pages”. For each input element we’ll have a label element. All labels will be styled like tabs.

<section class="tabs">
    <input id="tab-1" type="radio" name="radio-set" class="tab-selector-1" checked="checked" />
	<label for="tab-1" class="tab-label-1">About us</label>
	<input id="tab-2" type="radio" name="radio-set" class="tab-selector-2" />
	<label for="tab-2" class="tab-label-2">How we work</label>
	<input id="tab-3" type="radio" name="radio-set" class="tab-selector-3" />
	<label for="tab-3" class="tab-label-3">References</label>
	<input id="tab-4" type="radio" name="radio-set" class="tab-selector-4" />
	<label for="tab-4" class="tab-label-4">Contact us</label>
	<div class="clear-shadow"></div>
	<div class="content">
		<div class="content-1">
            <p>Some content</p>
		<div class="content-2">
            <p>Some content</p>
		<div class="content-3">
            <p>Some content</p>
		<div class="content-4">
            <p>Some content</p>

Every input element has a value, and we can always make an input selected by default by adding the checked attribute.


The first thing we need to do is to define some dimension and hide the inputs by setting their opacity to 0:

tabs {
    position: relative;
	margin: 40px auto;
	width: 750px;

.tabs input {
	position: absolute;
	z-index: 1000;
	width: 120px;
	height: 40px;
	left: 0px;
	top: 0px;
	opacity: 0;
	cursor: pointer;
.tabs input#tab-2{
	left: 120px;
.tabs input#tab-3{
	left: 240px;
.tabs input#tab-4{
	left: 360px;

The inputs will be covering the labels. It will seem, as if we click on the label, but actually we are clicking on the input. This is a trick that will also work in mobile browsers (in some mobile browsers, simply clicking the label will not focus the associated input).

Next, we will make the labels look like tabs by defining some neat style for them. Note that each of the labels has a different z-index. A box-shadow will add depth and realism to the tabs.

.tabs label {
	background: linear-gradient(top, #5ba4a4 0%,#4e8c8a 100%);
	font-size: 15px;
	line-height: 40px;
	height: 40px;
	position: relative;
	padding: 0 20px;
    float: left;
	display: block;
	width: 80px;
	color: #385c5b;
	letter-spacing: 1px;
	text-transform: uppercase;
	font-weight: bold;
	text-align: center;
	text-shadow: 1px 1px 1px rgba(255,255,255,0.3);
    border-radius: 3px 3px 0 0;
    box-shadow: 2px 0 2px rgba(0,0,0,0.1), -2px 0 2px rgba(0,0,0,0.1);

.tabs input:hover + label {
	background: #5ba4a4;

.tabs label:first-of-type {
    z-index: 4;
    box-shadow: 2px 0 2px rgba(0,0,0,0.1);

.tab-label-2 {
    z-index: 3;

.tab-label-3 {
    z-index: 2;

.tab-label-4 {
    z-index: 1;

Since we don’t want the bottom part of the box-shadow to show, we will cover it by using a :after pseudo-element with no content:

.tabs label:after {
    content: '';
	background: #fff;
	position: absolute;
	bottom: -2px;
	left: 0;
	width: 100%;
	height: 2px;
	display: block;

When we click on a tab (label), it will be different in style and color from the others. The important thing is to make sure that the “checked” label will be on top of all of the other layers in the tabs. So, we will give it the highest z-index:

.tabs input:checked + label {
    background: #fff;
	z-index: 6;

As mentioned before, the content division will contain all of the tab pages, and we will set its z-index to 5, just to be under the selected label. In this way, the box-shadow of content area will cover all of the other labels.

Inside the content area, there are four divisions and each of them has their own content. By default (when their respective label is not selected/clicked) we want them to be hidden. So, we set the opacity to zero and the z-index to 1. We cannot use the display: none property because it’s not supported in transitions.

.content {
    background: #fff;
	position: relative;
    width: 100%;
	height: 370px;
	z-index: 5;
    box-shadow: 0 -2px 3px -2px rgba(0,0,0,0.2), 0 2px 2px rgba(0,0,0,0.1);
    border-radius: 0 3px 3px 3px;

.content div {
    position: absolute;
	top: 0;
	left: 0;
	padding: 10px 40px;
	z-index: 1;
    opacity: 0;
    transition: all linear 0.1s;

.content div h2,
.content div h3{
	color: #398080;
.content div p {
	font-size: 14px;
	line-height: 22px;
	font-style: italic;
	text-align: left;
	margin: 0;
	color: #777;
	padding-left: 15px;
	font-family: Cambria, Georgia, serif;
	border-left: 8px solid rgba(63,148,148, 0.1);

When we want a content to appear (label clicked) we set the opacity to 1 and raise the z-index because we want this content division to be on top of all the others:

.tabs ~ .content .content-1,
.tabs ~ .content .content-2,
.tabs ~ .content .content-3,
.tabs ~ .content .content-4 {
    z-index: 100;
    opacity: 1;
    transition: all ease-out 0.2s 0.1s;

In this tutorial we just went through the basic example that will fade in/out the contents. You can find more styles and effects in the demos.

This tutorial is part of the CSS3 series on Codrops. Check out the other experiments:

Tagged with:

Rey Wang

Rey is a digital product designer based in Beijing, China. Contact & collaboration will be welcome.

Stay up to date with the latest web design and development news and relevant updates from Codrops.

Feedback 79

Comments are closed.
  1. Thanks for sharing this.
    What are the advantages of these Tabs versus the Spry Tabs that DreamWeaver uses?