The Wayback Machine - https://web.archive.org/web/20151210085355/http://staff.washington.edu/fmf/2010/03/05/jquery-tabs-basic-styling/
  • CSS, jQuery 05.03.2010

    jQuery’s tab widget makes it easy to create a set of tabbed sections which can be swapped for one another. At the same time, they can be configured to gracefully fall back if Javascript is disabled.

    While you can create very complex pages with jQuery Tabs, this post will cover the basics and some CSS for presentation options.

    These examples work with the current versions of the major browsers (Safari 4.0, Firefox 3.6, Opera 10.50, Internet Explorer 8). There are a few tweaks to make some of the examples work with IE 7, but much more CSS would need to be added to make them work with IE 6.

    Basic example

    With a minimum of markup and some CSS, we can set up a very basic set of tabs.

    Basic example
    First tab content.
    Second tab content.

    This example has very basic markup:

    <div class="tabs" id="statictabs">
        <ul>
            <li><a href="#static-tab1">First</a></li>
            <li><a href="#static-tab2">Second</a></li>
        </ul>
        <div id="static-tab1">First tab content.</div>
        <div id="static-tab2">Second tab content.</div>
    </div>

    The first thing to do is to make sure you’ve loaded jquery.js, ui.core.js, and ui.tabs.js in the head section of your document, so the jQuery Tabs code will be available to you.

    The class="tabs" is to make it easy to work with all the tab examples at the same time. The Javascript needed on this page to activate all the tabs is:

    jQuery (function () {
        jQuery ('.tabs').tabs ();
    });

    Throughout this page I’ll be explicity calling jQuery instead of using the more common shortcut $ since WordPress loads Prototype after jQuery, so $ will actually call Prototype.

    This snippet will find all objects with the class of tabs and call tabs () on the jQuery representation of them.

    You need at least this in your CSS for tabs to work:

    .ui-tabs .ui-tabs-hide {
        display: none;
    }

    jQuery will add several classes to your tabs object, including ui-tabs for the whole object and ui-tabs-hide for each tab which is not displayed.

    For the HTML itself, you can see that the items which will be content for the tabs need to have the id set, and the links in the list need to point to each. Only tabs which have links will get hidden, so that’s the first thing to check if your tabs all show up and you’re sure that the Javascript is being called.

    This example also has some CSS designed to make the tabs look more like tabbed folders:

    #statictabs .ui-tabs-nav {
        margin: 0;
        padding: 0 0 0 0.5em;
        overflow: hidden;
    }

    We need to clear all the margin and most of the padding on the list (jQuery Tabs adds the ui-tabs-nav class to the list) to make sure the tabs will be at the top of the content. The only padding is on the left, which will indent the first tab. We also set overflow: hidden because we want to use floats to make the tabs be on one line, but we also want the list block to contain the tabs. More explanation on how this works is available at the Clearing Floats section of my previous CSS and Floats post.

    #statictabs .ui-tabs-nav li {
        float: left;
        list-style-type: none;
        background: #d0d0d0;
        margin: 0 0.5em 0 0;
        padding: 0.25em 1em;
    }

    As mentioned above, we float the tabs so they will appear in a single row. We don’t want the bullet to show up in the list, so that gets cleared. We also set the background to be slightly darker than the selected tab and content area.

    We set the right margin so there’s space between the tabs, and the padding to give the text some space. The list item right margin matches the list block left padding. We could have just set the list item left margin instead, but IE 7 and earlier don’t always honor the left margin on the first tab, making it align with the left of the tab panel (it works with this example, but not when we add borders below).

    #statictabs .ui-tabs-nav li.ui-tabs-selected {
        background: #e3e3e3;
    }

    jQuery Tabs will add the ui-tabs-selected class for the list item of the current tab. We set its background to match the tab content.

    #statictabs .ui-tabs-nav a {
        text-decoration: none;
        font-size: 1.2em;
    }

    We make the tab’s text a little larger, and make sure it’s not underlined.

    #statictabs .ui-tabs-panel {
        background: #e3e3e3;
        padding: 0.75em 1em;
    }

    Each tab content will receive the ui-tabs-panel class, so we use that to set the background and give a little space around the actual content.

    Update 1/18/2011: If you would like the tabs to be below the content, the simplest way is to move the list below the tabs. If for some reason you can’t rearrange the source, it’s possible to move the tabs with just CSS. Doing that works best if you know the height of the tabs, and are sure they won’t wrap to a second line. The CSS for this example would be roughly:

    #statictabs {
        position: relative;
        margin-bottom: 1.7em;
    }
    #statictabs ul {
        position: absolute;
        top: 100%;
    }

    The rules on #statictabs ul are what move the tabs below the content by moving them below the enclosing #statictabs. The rules on #statictabs make sure that positioning of the list (i.e. the tabs) is relative to the content, and makes sure there’s room at the bottom for the tabs.

    Support for no Javascript

    If the browser does not have Javascript enabled, the above example will look like this:

    Basic example appearance without Javascript
    First tab content.
    Second tab content.

    We can make this look nicer by changing the markup slightly and adding some CSS, making the non-Javascript version look like this:

    Basic example, styled for non-Javascript

    First

    First tab content

    Second

    Second tab content

    Toggling the checkbox will enable and disable jQuery Tabs for this example.

    The HTML markup is slightly changed to add an h3 title in each tab’s content div. All the CSS for the first example is replicated for this one, with #statictabs changed to #statictabs2. The added CSS is:

    #statictabs2 ul {
        display: none;
    }
    #statictabs2 ul.ui-tabs-nav {
        display: block;
    }
    #statictabs2 .ui-tabs-panel h3 {
        display: none;
    }

    The first rule disables the list of links, but the next rule enables it again when tabs are activated. The last rule disables the h3 headers once tabs are enabled (and the ui-tabs-panel class is added to each tab panel).

    Adding borders

    Borders can be used to make the selected tab stand out even more than just slightly changing the color.

    Tabs with borders

    First

    First tab content

    Second

    Second tab content

    Not much CSS is needed to add the borders. In addition to the CSS used in the above example (except for #bordertabs being used instead of #statictabs or #statictabs2).

    #bordertabs .ui-tabs-nav {
        margin-bottom: -1px;
    }
    #bordertabs .ui-tabs-nav li {
        border: 1px #f21e1e solid;
        -webkit-border-top-left-radius: 0.5em;
        -webkit-border-top-right-radius: 0.5em;
        -moz-border-radius-topleft: 0.5em;
        -moz-border-radius-topright: 0.5em;
        border-top-left-radius: 0.5em;
        border-top-right-radius: 0.5em;
    }
    #bordertabs .ui-tabs-nav li.ui-tabs-selected {
        border-bottom-color: #e3e3e3;
    }
    #bordertabs .ui-tabs-panel {
        border: 1px #f21e1e solid;
    }

    The same border is set on both the tab panels and the individual tab links. In addition, the bottom margin of the list of links (with class ui-tabs-nav) gets a negative bottom margin to match the width of the border, which moves the panels up. This is to have the tab link bottom border align with the panel top border.

    There are also six attributes which set a border radius. This works for Webkit-based browsers (such as Safari), Gecko-based browsers (such as Firefox), and Opera as of 10.50. Each pair of attributes makes the top two corners rounded.

    The selected tab gets a bottom border to match the background. Normally since the panel is later in the document than the tab link, the panel’s border would be on top of the link’s border, and the appearance wouldn’t change. However, since floats appear over non-positioned items (see the Layering of float, block, inline section of the CSS and Floats page) the illusion is that the tab flows into the tab panel. Update 1/18/2011: I’ve rearranged the items so the default border-radius items come after the vendor-specific ones, which is the recommended order (so the non-vendor-specific ones take precedence).

    IE 7 and earlier, however, does not honor this property. The workaround for those browsers is to set z-index to make sure the border gets correctly covered. Since z-index doesn’t work with objects with static positioning, you also need to change that:

    #bordertabs .ui-tabs-nav li.ui-tabs-selected {
        position: relative;
        z-index: 2;
    }

    Larger click target

    This example has one more refinement, causing the whole tab to be clickable. If you move the mouse around the tabs on the previous examples, you’ll notice that you can only click directly on the text. However, you can click anywhere in the tab with this example. The first change is:

    #bordertabs .ui-tabs-nav a {
        display: block;
        padding: 0.25em 1em;
    }

    Setting the link to display: block allows us to manipulate the padding on all four sides, making the link larger. Since we want the whole tab to be clickable, the other change is to zero out the padding of the li, replacing the previous padding setting with:

    #bordertabs .ui-tabs-nav li {
        padding: 0
    }

    Tabs on the side

    It takes more CSS to make the tabs appear on the left of the panels. Using the same markup as the previous example, the result is:

    Tabs on left

    First

    First tab content

    Second

    Second tab content

    This tab will have several lines.

    We want to make sure it ends up being taller than the tabs on the left.

    That way we can demonstrate how to make sure each tab panel is at least tall enough to make sure the tabs are attached to something, but if the panel needs to be taller, its height will adjust.

    These tabs will not work on IE 7 and earlier. It should be possible to do so with more CSS, but this post is concentrating on current browsers (the previous IE 7 workarounds were minimal). This example has quite a bit of added complexity, but demonstrates several CSS techniques. It builds on the previous one with borders around the tabs, but using #lefttabs instead of #bordertabs.

    #lefttabs {
        overflow: hidden;
        position: relative;
    }

    The first thing we need to do is make the outer div a position container, and make sure that anything which may appear outside is hidden. This will be important when we work with the bottom of the tab panel.

    #lefttabs ul.ui-tabs-nav {
        display: block;
        width: 6em;
        float: left;
        padding: 0;
    }

    Since we want the list of links to appear on the left, we float the whole list and give it a width, since we need to know that width to be able to make the borders align.

    We can’t use a negative margin to nudge the tab panel to the left, since we’ll be setting margin-left to make sure the panels are clear of the float. We’ll be adjusting the links themselves below to fix up the border between the links and the panel.

    Lastly, we need to make sure there is no padding on the list block. We’ll be using margins to regulate the spacing between the individual tab links, and we want to make sure the tabs are full width (we had already zeroed out the margin of the list block in the first example).

    #lefttabs .ui-tabs-nav li {
        width: 6em;
        background: #d0d0d0;
        margin: 0.5em 0;
        border: 1px #f21e1e solid;
        border-right-width: 0;
        -webkit-border-top-left-radius: 0.5em;
        -webkit-border-bottom-left-radius: 0.5em;
        -moz-border-radius-topleft: 0.5em;
        -moz-border-radius-bottomleft: 0.5em;
        border-top-left-radius: 0.5em;
        border-bottom-left-radius: 0.5em;
        text-align: right;
        list-style-type: none;
    }

    Setting the background and type of list are the same as the previous examples. The border is slightly different in that it has no border on the right and rounds the two corners on the left (instead of the corners on the top). We also make sure the text is aligned to the right, so the text is closer to the tab panel. Update 1/18/2011: The border-radius items were rearranged in a similar manner to the previous example.

    As mentioned above, we use margins on the list items to space the tabs. The margins collapse since we’re setting them on the top and bottom, whereas on the horizontal tabs we set the margin on only one side.

    The most subtle aspect in this definition is the width. Remember that the width of the entire list is 6em. Were we to not specify a width on the list items, their widths would be 6em including the 1px left border. Since we do specify the width, they are exactly 1px wider than the list block (since borders and padding are not included when a width is specified). Therefore, the link overlaps the border of tab panel by that 1px. Since we set a background color, and the list block is a float, it obscures the tab panel’s border.

    Since we don’t worry about this example working with IE 7, we don’t need to set the z-index to make sure the list item is indeed over the border.

    #lefttabs .ui-tabs-nav a {
        border-right: 1px #f21e1e solid;
    }
    #lefttabs .ui-tabs-nav .ui-tabs-selected a {
        border-right-color: #e3e3e3;
    }

    This is where we make sure the red border reappears for the non-selected tabs. Remember that the link has been set to a block so it would take up the entire li item. By setting the right border, we are making the right side of the list item have the red color, and since we know the right edge of the list item exactly overlaps the border of the tab panel, that border looks continuous. The link in the selected tab item gets a right border which matches the background, making the tab look as if it flows into the tab panel.

    Another method to make the tab flow into the panel would be to remove the right border completely, letting the list item’s background color obscure the tab panel border. However, that would cause the text to be too far to the right (by the same amount as the border’s width) when the tab is selected, which is why I chose to change the border’s color instead.

    Since the border widths are set with pixels, the math is pretty simple. Were we to set the border widths using relative units (such as 0.12em) we’d need to take the larger size of the link text into account when declaring the border’s width. Since the link text font-size is 1.2em, then a tab border of 0.12em would translate to the border of the link being 0.12em/1.2 = 0.1em.

    #lefttabs .ui-tabs-panel {
        margin-left: 6em;
        margin-bottom: -30000px;
        padding-bottom: 30000px;
    }

    The first thing this definition does is to make sure the tab panels clear the tab links. As discussed above, the left margin exactly matches the width of the tab block, making the tab panel’s left border be in the right place.

    Without the next two lines, the tab panel will only be as large as its content. If you click on the second tab, you’ll see that the panel does expand when there’s quite a bit of content. If you click on the first tab, however, you’ll see that the panel is larger than the content to make sure the tabs on the left still appear to be attached to something.

    The large positive padding makes the tab panel extremely tall, but the large negative margin adjusts it so only the necessary content needs to be shown. Since the tab list on the left is floated and the surrounding div is a flow root (because of the overflow: hidden), if the list is taller than the tab panel, the #lefttabs div will expand to fit. Since the tab panel has such a large amount of padding on the bottom, the background color and border will extend down, but won’t show beyond the bottom of the #lefttabs block, since we said that all overflow should be hidden.

    The last thing to fix is the bottom border on the tab panel, since the large bottom padding makes the border be well outside the visible area of #lefttabs. We need to create a dummy block to draw the border. We could have put it into the HTML, but since we’ll only need it if we’re using jQuery, we go ahead and create it in Javascript:

    jQuery (function () {
        jQuery ('#lefttabs').append ('<div class="bottomborder"></div>');
    });

    The CSS for this block is:

    #lefttabs .bottomborder {
        position: absolute;
        width: 100%;
        bottom: 0;
        margin-left: 6em;
        border-bottom: 1px #f21e1e solid;
    }

    We want the border created by this block to be at the bottom of #lefttabs, so we position it absolutely. Because of that, we need to give it a width. We can’t compute the width less 6em (the left margin for the tab panel), but we do know that #lefttabs has overflow hidden. That lets us go ahead and set the width to 100% and then set the left margin to match the tab panel, knowing the overhang on the right won’t show since it’s outside #lefttabs. If the right side of the tab panel weren’t at the right edghe of #lefttabs, we could make the dummy block be nested; the outer block would have margins or padding so the inner could be correctly positioned horizontally, and the inner block would have the border.

    We know it’s safe to just put the border at the bottom of #lefttabs because we know the bottom of the tab panel will always be at the bottom the container.

    Posted by fmf @ 5:47pm

  • 10 Responses

    • Hi! Recently I update a website and I add the jQuery tab inside the page, but here come a problem to me when I view in IE8. For first time loading, below the footer seem retain some space for the content of the tab which i already hiding. It works for other browser even for IE6 and 7 but just problem come in IE8. I try search solutions but unfortunately i cant get it.
      Sorry if this annoying u. I’m newbie for this.
      I hope that I can figure out what is going on.
      Thanks you!

      • Sorry for the delay – I was out of the office. My first stab at a recommendation would be to make sure your page has a Doctype at the top, to make sure the browsers are using standards mode. Do you have an example to look at? How do things look in browsers other than IE?

    • Frank,
      Not only is this coherent, grammatically correct, and useful, it is concise and has well written examples.

      Thanks for doing this.
      -Myles

      • I’ve made an update to this page to show how to move the tabs to the bottom. In order to do both, you’ll need to use CSS and make sure your list can be split into two blocks.

        Since jQuery tabs only allow one list, you can fake it by putting a divblock around the items you want on the bottom. You then use the CSS from the example showing tabs on the bottom, but instead of moving the whole list, you just move the div.

        I would highly recommend doing usability testing if you decide to implement this. It does seem like an interesting alternative to two rows of tabs (which I’ve never been a fan of).

        Also, it’s not clear to me whether putting a div around a group of list items would validate. However, I’m guessing most (all?) browsers would render the tabs as you want. Be sure to test across several browsers to be sure.

    • I’m really enjoying the theme/design of your weblog. Do you ever run into any web browser compatibility issues? A few of my blog readers have complained about my blog not operating correctly in Explorer but looks great in Opera. Do you have any advice to help fix this problem?

      • Thanks for your kind words. Admittedly, I just took one of the free themes from wordpress.org, so a lot of the work was already done.

        If you’re unable to directly test in IE, there are some sites which let you queue a URL and they’ll give you a screenshot of how it looks in various browsers. You can’t test dynamic things, but it can give you a general idea.

      • You can change the color of a visited link with CSS’s :visited selector. I’d suggest doing a search for “css visited link” for more information.

    • Useful information. Thank you! I have never liked the jQuery tabs default appearance as it looks to cluttered and unclean with unnecessary borders.

    Leave a Reply