posted on:January 27, 2011

Styling Full Width Tabs with CSS3


In this article I will demonstrate how to create full width "browser-like" tabs using pure CSS3 and some HTML5 markup. This article includes whole lot of new CSS properties such as box and text shadows, border radius and CSS gradients. That means a lot of vendor prefixes in the code :).

CSS3 tabs

Of course, not all browsers support these properties, so we need to make sure that everything degrades nicely. I mean as nice as a it could be, right?

It degrades from this (Safari)

Tabs in Safari

to this (IE8)

Tabs in IE8

Markup

First let’s take a look at the markup. In this example I am using HTML5 elements.
Head of the document looks like this:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Tabbed Layout</title>
<link rel="stylesheet" href="css/screen.css" type="text/css" media="screen" />
<!--[if IE]> <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]-->
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript" src="js/tabbed.layout.js"></script>
</head>

We are using John Resig’s HTML5 Shiv to make sure we can properly render HTML5 elements in all browsers, and I am including a Easy Framework’s tab script just to add behavior to the tabs.

Next in the markup structure is the header…

<header>
<h1>Some cool goes title</h1>
</header>

…and then we go to the nav element. This element contains actual clickable tabs:

<nav> 
    <ul>
        <li><a href="#tab1">Tab 1</a></li>
        <li><a href="#tab2">Tab 2</a></li>
        <li><a href="#tab3">Tab 3</a></li>
        <li><a href="#tab4">Tab 4</a></li> 
    </ul>
</nav>

We link the tabs to the section elements further down in the markup structure:

<section class="tab" id="tab1">
<p>Section number 1</p>
</section>

<section class="tab" id="tab2">
<p>Section number 2</p>
</section>

<section class="tab" id="tab3">
<p>Section number 3</p>
</section>

<section class="tab" id="tab4">
<p>Section number 4</p>
</section>

As far as the necessary markup goes, this is it. Pretty simple!

CSS3 Magic

First let’s edit the header. Header has fixed height and we added a subtle CSS gradient to it, from darker to lighter:

header{
    height:32px;
    overflow:hidden;
    background:#e1e1e1;
    background:-webkit-gradient(linear, left top, left bottom, from(#d1d1d1), to(#e1e1e1));
    background:-moz-linear-gradient(top,  #d1d1d1,  #e1e1e1);
    padding:0 5px;
    }

Nav element has fixed height as well, list items inside are floated to the left and have the same width. We are also adding CSS gradients along with bottom border radius and box shadow. (vendor prefixes galore)

nav li{
    list-style:none;
    float:left;
    height:24px;
    line-height:24px;
    -moz-box-shadow:0 0 3px #888;
    -webkit-box-shadow:0 0 3px #888;
    box-shadow:0 0 3px #888;
    -webkit-border-bottom-right-radius:3px;
    -webkit-border-bottom-left-radius:3px;
    -moz-border-radius-bottomright:3px;
    -moz-border-radius-bottomleft:3px;
    border-bottom-right-radius:3px;
    border-bottom-left-radius:3px;
    margin:0 2px;
    width:200px;
    overflow:hidden;
    position:relative;
    background:#ccc;
    background:-webkit-gradient(linear, left top, left bottom, from(#ccc), to(#aaa));
    background:-moz-linear-gradient(top,  #ccc,  #aaa);
    }

Selected tab should blend into header so the colors must match. "Ending" color of the header gradient must be "starting" color of the selected tab. Also make sure that you define matching regular background colors for browser that don’t support CSS gradients.

nav li.selected{
  background:#e1e1e1;
  background:-webkit-gradient(linear, left top, left bottom, from(#e1e1e1), to(#d1d1d1));
  background:-moz-linear-gradient(top,  #e1e1e1,  #d1d1d1);
  }

Styling the anchor’s inner shadow

Now here’s a little trick. I guess you are familiar with box-shadow property and how it works. What we can define is horizontal offset, vertical offset blur and a color. Another cool option that allows us to have inner shadows is the inset attribute.
Here is our problem… on non selected tabs, we need to have only top shadow, no shadows from the side. That is not doable with the usual settings

What we’ll do is:

  • add inner shadow to anchor element with vertical offset only
  • make a nested anchor element wider than the parent LI element
  • position anchor absolutely inside the LI element
  • set overflow to hidden on LI element

That way we will simply hide the side inner shadow and have only top shadow visible. This is small detail, but without it the entire tab would not look natural (as if the header drops a shadow on it).

Take a look at the graphic to (hopefully 🙂 ) understand it better.

Hiding side shadows

Here’s the CSS for the anchor element:

nav li a, nav li a:visited, nav li a:hover{
  list-style:none;
  display:block;
  position:absolute;
  top:0;
  left:-2px;
  height:24px;
  line-height:24px;
  width:204px; 
  text-align:center;
  color:#333; 
  font-size:11px;
  text-shadow:#e8e8e8 0 1px 0;
  -moz-box-shadow:inset 0 1px 1px #888;
  -webkit-box-shadow:inset 0 1px 1px #888;
  box-shadow:inset 0 1px 1px #888;
  } 

Selected anchor doesn’t have an inner shadow:

nav li.selected a{
  -moz-box-shadow:none;
  -webkit-box-shadow:none;
  box-shadow:none; 
  } 

JavaScript

Last but not least, I added a simple tab script, because without it, tabs… well… wouldn’t make that much sense. This script is taken directly from my Easy front-end framework code.

tabs = function(options) {
    
    var defaults = {  
        selector: '.tabs',
        selectedClass: 'selected'
    };  
    
    if(typeof options == 'string') defaults.selector = options;
    var options = $.extend(defaults, options); 

    return $(options.selector).each(function(){
                                
        var obj = this;	
        var targets = Array();

        function show(i){
            $.each(targets,function(index,value){
                $(value).hide();
            })
            $(targets[i]).fadeIn('fast');
            $(obj).children().removeClass(options.selectedClass);
            selected = $(obj).children().get(i);
            $(selected).addClass(options.selectedClass);
        };

        $('a',this).each(function(i){	
            targets.push($(this).attr('href'));
            $(this).click(function(e){
                e.preventDefault();
                show(i);
            });
        });
        
        show(0);

    });			
}
// initialize the function
tabs('nav ul');

Note that we are passing a selector as a parameter to the function. This selector must be a unordered (or ordered) list of the tab navigation.

Take a look at the demo or Download files

That is it! In my next article I will take this one step further and create a full screen tabbed layout so stay tuned!

Enjoyed the article?

Then don't miss our next one! Subscribe to our RSS feed or share it with your friends.

DeliciousStumbleUpon RedditSubscribe

Comments (13 Comments)

  1. Red
    January 28, 2011

    Very nice result, thanks for sharing!
  2. Joost
    January 29, 2011

    Looks very sexy. Nice way of 'clipping' the box-shadow. Since the tabs have a fixed width, it would be very trivial to have an image fall-back for the more css3-challenged browsers out there.
  3. Web Design Company
    January 29, 2011

    CSS3 is modularized and consists of several separate recommendations. If we want to follow the development of CSS3, this is the place to start to learn..Really fantastic post...
  4. Petr Lev
    January 30, 2011

    Nice article, thanks
  5. Izdelava internetne strani
    January 30, 2011

    Awsome tutorial. Just what i was looking for my next website navigation! Thanks.
  6. Laura
    January 31, 2011

    Great blog. I love your articles so much. Keep on! Laura
  7. jack
    February 1, 2011

    Hi its great i enjoy reading your post
  8. Joseph Taylor
    February 1, 2011

    Very nice demonstration! I'm salivating over the possible uses!
  9. Robert Visser
    February 1, 2011

    One aspect I'd like to see implemented is to pass the #tab1, #tab2, #tab3, #tab4, etc to the URL. In all of our A/B testing enabling an ability to bookmark individual tabs garners better UX responses -- at least in instances where tabs were used for primary page navigation as opposed to loading content into a small window. In the full page version, I'd like to see the CSS take advantage of orientation media queries. Thanks for the post.
  10. Chris F.A. Johnson
    February 2, 2011

    A good article, apart from using fixed heights (the demo doesn't work for me; the text is cut off at the bottom).
  11. csabi
    February 3, 2011

    Hi! I just love your tutorial! Congratulations! I`we just opened a tutorials indexing website and I would like to ask you to submit your tutorials, it will bring you some extra traffic Please give a chance for my website: http://www.tutorialswindow.com Thanks!
  12. stevewckrt
    February 4, 2011

    Very nice demonstration! http://www.bugsketch.com Watch live football games streaming on your computers.Never miss another football game again. Our instant access site allows you to Watch Live Football Online On Your PC minutes after subscribing. We provide access to all of the latest football streams and live soccer feeds.
  13. san fransisco
    February 8, 2011

    It's helping me in my work.Thank you so much.

Sorry, the comment form is closed at this time.