(Better) Tabs with Round Out Borders

Jan 10 2012
98
The following is a guest post by Menno van Slooten. You might notice we've been down this road before, but I quite like Menno's approach here. The end result proves you can get a little fancier with the design than I originally did, with borders, gradients, and shadows and while actually using less elements.

A good-looking tab control usually has one feature that I've always found impossible to reproduce without images: borders that bend to the outside at the bottom of each tab. In this article I would like to show how you can use the CSS :before and :after pseudo elements to create this effect without using images. First, let's start with some basic markup.

The markup

<ul class="tabrow">
    <li>Lorem</li>
    <li>Ipsum</li>
    <li class="selected">Sit amet</li>
    <li>Consectetur adipisicing</li>
</ul>

This would be about as basic as you can get. Not a lot of elements to work with here, but it will do.

Getting started

To get started, let's get rid of the default <ul> and <li> styling and get these babies in line.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow {
    text-align: center;
    list-style: none;
    margin: 0;
    padding: 0;
    line-height: 24px;
}
.tabrow li {
    margin: 0 10px;
    padding: 0 10px;
    border: 1px solid #AAA;
    background: #ECECEC;
    display: inline-block;
}

Selecting a tab

The selected tab should of course be clearly visible.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow li.selected {
    background: #FFF;
    color: #000;
}

Getting to the bottom of things

Every tab control needs a well-defined bottom edge. It won't do much now, but later it will help emphasize the effect of the selected tab being on top.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow {
    position: relative;
}
.tabrow:after {
    position: absolute;
    content: "";
    width: 100%;
    bottom: 0;
    left: 0;
    border-bottom: 1px solid #AAA;
    z-index: 1;
}

Here we introduced our first :after pseudo-element. Basically, :after appends another child to an element. It's not in the DOM (which is why it's called a pseudo element), so it is not a real child but it is completely stylable, as long as you add some content, in this case a single space character.

In my opinion, the terms :before and :after are slightly confusing since the pseudo's aren't actually added before or after the element they apply to, but are inserted as children. This is also why you can't apply :before and :after to elements that can't contain children ("no content" elements), like <input>.

In this case, we use the pseudo element to create a bottom border that doesn't influence the tabs' positioning. We could have just put a bottom border on the <ul> but that would've made the next step a little trickier.

Above and beyond

Now, an essential part of a convincing looking tab control, is that the selected tab sits in front of the edge while the rest fall behind the edge. To do this, we change its bottom border and do some z-index magic.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow:before {
    z-index: 1;
}
.tabrow li {
    position: relative;
    z-index: 0;
}
.tabrow li.selected {
    z-index: 2;
    border-bottom-color: #FFF;
}

Around the bends

It is now time to add the elusive border that bends to the outside and we'll use :before and :after for this. Let's take this step by step and first just put everything in position.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow li:before,
.tabrow li:after {
    position: absolute;
    bottom: -1px;
    width: 6px;
    height: 6px;
    content: " ";
}
.tabrow li:before {
    left: -6px;
}
.tabrow li:after {
    right: -6px;
}
.tabrow li:after, .tabrow li:before {
    border: 1px solid #AAA;
}

Don't be such a square

You can probably see where this is going. Let's remove the borders we don't want and add some rounded corners.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow li {
    border-top-left-radius: 6px;
    border-top-right-radius: 6px;
}
.tabrow li:before {
    border-bottom-right-radius: 6px;
    border-width: 0 1px 1px 0;
}
.tabrow li:after {
    border-bottom-left-radius: 6px;
    border-width: 0 0 1px 1px;
}

Cutting corners

There's something not quite right about this result. Let's look at it up close. As you can see both the original straight corner as well as the rounded corner are visible. We need to somehow get rid of the straight corner. To do that, we will cover it up with a shadow. To illustrate what's going on, let's make the shadow stand out a little bit.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow li:before {
    box-shadow: 2px 2px 0 red;
}
.tabrow li:after {
    box-shadow: -2px 2px 0 red;
}

Almost there

As you can see, the red shadows completely cover up the square corners we would like to hide. If we give the shadow the correct colors the illusion is complete.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow li:before {
    box-shadow: 2px 2px 0 #ECECEC;
}
.tabrow li:after {
    box-shadow: -2px 2px 0 #ECECEC;
}
.tabrow li.selected:before {
    box-shadow: 2px 2px 0 #FFF;
}
.tabrow li.selected:after {
    box-shadow: -2px 2px 0 #FFF;
}

Pieces of flair

All that's left to do now is adding a sprinkling of gradients and shadows to spice it up just a little bit.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow li {
    background:      -o-linear-gradient(top, #ECECEC 50%, #D1D1D1 100%);
    background:     -ms-linear-gradient(top, #ECECEC 50%, #D1D1D1 100%);
    background:    -moz-linear-gradient(top, #ECECEC 50%, #D1D1D1 100%);
    background: -webkit-linear-gradient(top, #ECECEC 50%, #D1D1D1 100%);
    background: linear-gradient(top, #ECECEC 50%, #D1D1D1 100%);
    box-shadow: 0 3px 3px rgba(0, 0, 0, 0.4), inset 0 1px 0 #FFF;
    text-shadow: 0 1px #FFF;
    margin: 0 -5px;
    padding: 0 20px;
}

If you're wondering about browser compatibility, it's exactly as you'd expect: everything but IE. It's very possible that it'll work in IE10, but I haven't had the chance to test with a preview release. Since IE8 and IE9 do support :before and :after but not border-radius you'll have to create a separate stylesheet for them if you want to give their users a nice visual experience.

View Demo   Download Files

Editor's note: I added anchor links inside the tabs in the demo since I think it's the most likely case that tabbed navigation like this have them. Most likely, they would have an href attribute that would link to the content they go with by id, and that behavior would be controlled by JavaScript. The fact that this tutorial doesn't need the anchor links for the extra pseudo elements is further testament to it being better than my original.

Subscribe to The Thread

  1. Wow. Those are gorgeous!

  2. Nick

    Awesome!!

  3. Hey!
    Very good technique, and this works perfectly in IE10 on W8!

    • leipie

      Hey!
      Seems to work fine on Opera 11 too ;)

  4. Thanks Chris , but how to achive that effect in the Older browser the ME- rang of visitors are 75% using IE6-IE7-IE8

    so are there any easy ideas !!!

    • Chris

      Try some PIE, there are some css3 things it doesn’t do but it does allow you to use gradients and outer shadows. It works on the fly too so it is pretty seamless.

      http://css3pie.com

    • Kevin

      My team used CSS3 pie on a fairly large website, and IE7 rendering performance becomes very bad. It slows down the PC it’s on, and clicking on something takes a full second or more to change the state appearance of. Make a stand to not support IE7. There really is no choice as we’ll all do it some day. Use a JS Shim for :before and :after support if you really must. IE8 degrades okay into square corners and flat gradients – and that’s fine. IE9 gets rounded corners but no gradients. All this, really is okay. Different browsers can get different designs. Nicer browsers will reward users effort to upgrade with a nicer site. It’s a reward system we need to encourage.

  5. Beautiful :)

  6. theTimmy

    What about the tops of the interior tabs? the outside tabs look nice and rounded, but the interior is not as clean.

  7. Rafael

    Hey Chris!

    The tabs do work nicely in IE9… IE9 has border-radius support.

    • Indeed it does. Though many may not know that you have to specify all four corners for it to work. For example, the short cut:

      border-radius: 4px;

      You need to do this instead:

      border-radius: 4px 4px 4px 4px;
    • I don’t think this is correct, Steve. The border-radius property works fine in IE9 with a single value. That being said, I don’t have a native install of IE9 (I have IE8 and IE10, which allows “IE9 mode”), but I used Adobe browser labs to do a quick test, and the rounded corners work fine. Also, a site like caniuse.com usually has notes on that type of partial support, and I don’t see anything there about that.

      In the section of the article where Menno mentions lack of border-radius support, I think he meant lack of support for IE8, not IE9. Chris might want to correct the wording in that sentence.

      The only way (I think) that someone would get the impression that IE9 didn’t support border-radius was if they were inadvertently in “IE8 mode” in their IE9 install (I’ve done this before with IE8 as IE7), or the document they were testing in was using the “IE7″ meta tag in the head.

    • I do have a IE9 native install and I can confirm that

      border-radius:  4px;

      works just fine. There is no need to have four values for equally rounded corners.

  8. I love it! The way you used all of these techniques is ingenious.

  9. Sweet and clean. Thanks Chris.

  10. Wow, these tabs are amazing. I guess I may _have_ to use them in upcoming projects! Thanks a lot!

  11. WOW!

  12. This is such a clear, succinct explanation of something I would have expected to be more complicated. The final result is so crisp and clean, but not boring. I’ll definitely be working rounded tabs into a project sometime soon, thanks for the code AND the design idea!

  13. They work fine in IE9! The only thing that doesn’t show is the slight gradient shadow on the non-active tabs in IE9, but the borders work great otherwise.

  14. gerorg

    Hello

  15. Dave

    IE9 does support border-radius. The tabs look great!

  16. Maurycy

    You forgot to add border:

    .tabrow li:before, .tabrow li:after { border: 1px solid #AAA; }

    Great article, thanks!

  17. Great Tutorial. Used it to make trapeze shaped tabs as the ones Google Chrome uses and this is my result:
    http://dabblet.com/gist/1590824

    Looks nice :)

  18. That is just awesome. Have always stopped at Above and beyond step (maybe with rounded corners on the top of the tabs and a little gradient. But the finishing touches really make the difference. Cheers

  19. Thanks for all the positive comments everyone!

    @islam barakh: it’s not very hard to achieve this effect in IE6-8, it just requires a lot more HTML, CSS and (more importantly) images.

    @Maurycy: I’ll ask Chris to make the correction, thanks!

    @Tom: That’s really ingenious and those look great. I’m definitely going to use that.

  20. Neil

    Nice!

  21. niiice…

  22. Adam Phin

    Use CSS3 Pie and you will have those rounded corners in IE.
    http://css3pie.com/

  23. great tutorial, thanks.

    I would add one thing – in demo I would make entire area in tab clickable – not only text.

  24. Tabs look cool.

    But unless I’m missing something, using Safari 4.1.3, the difficult rounded out bottom tabs still clearly show the vertical line that you are attempting to ‘hide’ with the shadow.

    While in Firefox 3.6.23 (on Mac) none of the tabs have rounded corners at all – they are all still square-cornered!!!

    Cheers
    I

    • For Firefox 3.6 the -moz- prefix is required.

      border-radius (no prefix) only works for Firefox 4+.

    • Martyyyy

      Re: entire area in tab clickable .
      Move the padding from the .tabrow li {}
      to
      .tabrow a{color:#555;text-decoration:none; padding:2px 20px;}

  25. Asgaroth

    Really nice, excelent work as always!

  26. What a great effect. I’m sure I could use it on one or two of my sites.

  27. Tabs look cool.

    But in Safari 4.1.3 the bottom round flanges still show the vertical line that you were trying to ‘hide’ with the shadow.

    And in Firefox 3.6.25 (Mac) – all the tabs are showing as square-cornered with no rounded corners at all.

  28. iDGS

    That shadow thing, to hide the corners? Love. It!

  29. What’s going bad: on Android css shadows with 0 blur value simply don’t show themself at all.

    • On 2.3 version, at least. I don’t know if that bug is present in other releases. A really old bug.

    • Maybe you expect too much. It’s only poor Android with big marketing.

  30. wooww its so amazin’ its so clear

  31. Andy

    Aaah, good one.

  32. At last! Thanks a lot for sharing, chris..

  33. charbs

    I love that fact that the demos are right there on the page!

  34. saeed

    not support IE :(

  35. T.J. Crowder

    Pretty! It’s not just border-radius that keeps it from working in IE8, but also box-shadow (link). Using pseudo-elements, thereby leaving IE6 and IE7 behind, is probably fine for people not targeting China now, but we’re likely to be stuck with IE8 for a while.

    • Try using CSS3 PIE:

      http://css3pie.com/

      Enables the use of border-radius and box-shadow in IE back to IE6.

      Note that many servers won’t allow the direct use of the PIE.htc script and you will need to use the PIE.php script to load it.

  36. Thanks Chris. This is really useful…

  37. wow, gorgeous

  38. Kim Christiansen

    The first and last pseudo classes can be used in IE 6-8 with the polyfill Selectivizr:
    http://selectivizr.com/

    • Actually Selectivr is awesome but it doesn’t do :before and :after

    • yashu

      Before and After Will not be there in javascript!!!

      The author wrote this article keeping in mind to introduce “:AFTER” & “:BEFORE”… in HTML….

  39. Impressive! I tried to complete the same effect last week but I used 3 pseudo-element: http://www.swordair.com/blog/2012/01/747. Using box -shadow to hide square corners is creative. Awesome work!

  40. Top stuff indeed. I’m continually amazed at what can be done with CSS.

    Reason #485 to stop using so many images in website builds!

  41. This trick is really clever never seen something as good as this before and I have already bookmarked it (on my website) for later reference :)

    Well done.

  42. Your explanation is incredibly clear and concise. I can literally feel the excitement running through my veins with the possibilities for this technique! WITHOUT IMAGES!! YEW!

    For so long I’ve had to deal with unnecessary markup, but this method creates such beautiful tabs without that need.

    For everyone complaining about IE8 – remember that it’s not always important for a website to look exactly the same in every browser. Often I like to add these niceties for those with a capable browser and provide a “close enough” fallback.

    I do think I will be adapting your step by step approach toward styling from now on. It really seems to avoid unnecessary code. Great work! An inspiration.

  43. The shadow still shows a little in the bottom corners. Not a lot, but it’s noticeable nonetheless. Worse though is the border equals background color trick. It hides what is probably one of the hardest part of css’ing tabs and will fail when you don’t have a one-value background color.

  44. Really great!

  45. Tricky! :)
    Great article!

  46. stryju

    i used the same concept ( self-developed ) on css summit ’11 for chris’ challenge – guess i’m not that original …

  47. illufox

    Had to change .tabrow li to margin: 0 5px; and .tabrow li:before and :after to left: -8px;. But the corners are still showing on the little boxes between the tabs. Setting border width to 0 for top left and top right does not hide the borders for some reason. I tested this in Safari and Firefox.
    Also, the end result is pretty ugly as there’s a large shadow below the tabs that makes the box shadows stand out. I could remove the shadow but then the tabs wouldn’t have that nice shadow behind them. Disappointing solution for sure!

    • stryju

      remove closing tags for elements ( so no ) or remove ANY whitespace between them ( if u want to be xhtml-compatibile ) – one thing about using inline-block elements

    • stryju

      oh sorry, ignore the post – didn’t uderstand your problem correctly, i guess :-P

  48. Nicely done and easy to follow. It’s nice to see that this can be done using no images and a little bit of CSS3. Too bad IE doesn’t support this yet…it’s a shame.

    • Aaron, IE9 supports it nicely. So, maybe shame to you for such message and knowledge.

    • Yes it’s doesn’t support for IE9- but in IE9 very nice…

  49. Hi!

    Really nice tabs but I have a little problem with it!!

    The script removing the selected status kills all my other “selected” links on the page.

    Anyone out there who knows to fix it??

    Thanks a lot!

    cenco

    • stryju

      try this:

      
      $(function(){
        $( ".tabrow" ).on( "click", "li", function( e ){
          var $this = $( this );
          e.preventDefault();
          $this.parent().find( ".selected" ).removeClass("selected");
          $this.addClass( "selected" );
        });
      });
      
  50. That’s fancy. Nice demo.

  51. Sultan

    thanks chris ..

    great tutorial ..

    waiting for more tutorials ..

  52. MikeR

    Cant his work within a table format… instead of using the :after or :before on an <li> , using it on a <td> for instance. I briefly tried this with no luck so if someone more knowledgeable than I can answer that would be appreciated.

  53. Chris I am a big fan of your work and this is just a master mind at work. I just wanted to know where the hell did you come up with the idea to do this with css anyone else would have done it with images but you sure are the master css

  54. This is a great technique! I wouldn’t have thought of this.

  55. This is really nice. Thanks for sharing.

    Two point of clarification, though. When you say:

    In my opinion, the terms :before and :after are slightly confusing since the pseudo’s aren’t actually added before or after the element they apply to, but are inserted as children.

    I think that’s actually misleading. W3C says they go after in the DOM tree, not as descendant children. See:

    http://www.w3.org/TR/CSS2/generate.html

    And then you say that:

    This is also why you can’t apply :before and :after to elements that can’t contain children (“no content” elements), like .

    which is simply false. Try out:

    input:after {
    	content: "check me out Menno!";

    on an input type=”radio”…

  56. But it’s not compatibly with IE7 :) and you have some lib js for that’s?

  57. That is a very cool, so good that you’ve shown how it can be done with just CSS too, this will make it so much easier to incorporate it into a few of my clients CMS’s.

    I’m going to start playing around with it now

  58. Thanks man… U did a great job…

  59. Ira Hanson

    If you use <label> tags and a group of radio buttons, you can perform the tab switching with no JavaScript whatsoever.

    Demo using jsFiddle

  60. wobla

    This is awesome. The only problem is zooming – even a slight change makes the bottom part of the tab look crappy. Is there any way around that, beyond telling users to not zoom?

  61. @stryju

    That’s awesome! Thank you very much for your help it works perfectly!

    Regards,

    cenco

  62. great, thanks for the trick

  63. Brad

    Wonderful appearance but couldn’t get it to work on localhost with the e.preventdefault. tried the script on this page and the one that came with the download. Otherwise super idea!

    • Hey Brad. You’ve just solved my problem after reading your comment regarding localhost with “e.preventDefault” enabled. I removed “e.preventDefault” and it works fine. When I’m ready to upload pages that use “(Better) Tabs with Round Out Borders”, would I need to replace “e.preventDefault?”

      Any comments would be much appreciated.

    • Brad

      I don’t know Jack, Ive never got this up on the server because some other things popped up. Localhost to my knowledge should act like like on the web. I still use the tabs on my local pages, just without the js. I do note that its working for others so it is a good deal and excellent appearance.

    • Thanks Brad, yeh you’re right about the localhost acting like on the web. Just started using localhost, silly Q. Anyway this CSS is keeping me up till all hours, I love it, I haven’t touched a table in weeks thanks to sites like this!

  64. Really nice Chris! Any time I’ve wanted to do nice looking nav like this with several states, I’ve used the old huge-image-sprite Apple technique, which works fine, but to get pretty damn close with no images is an achievement! Nice work!

  65. I’ve created a dabblet for this example:

    http://dabblet.com/gist/1633247

    so you can play around with css in the browser

    Robin

  66. Awesome stuff!

    I recommend border-bottom: 2px solid white; on the selected tab, though. The extra border pixel will cover up the unsightly border below the tab (at least for me in Chrome)

  67. Thanks for the tip there are some great articles on here!

  68. herbyderby

    Thank you very much. Quite the amazing ‘little’ tute on this! And the shocker: doesn’t work on earlier versions of IE…ugh.

    Nonetheless, thanks again!

  69. Will Drotar

    Nice and simple, thanks!

  70. Thanks for this amazing article. I must say your blog provides much useful information. I think this was really an interesting article. In fact I enjoyed reading this article. Keep sharing such more fascinating blog.

  71. Kake

    Hi

    Nice tabs.. Is there a way to left align the tabs? (if I try to manipulate the .tabrow text-align: left;
    The first tab looses its leftside..

  72. Thanks to both Chris Coyier and Menno van Slooten for this wonderfull piece of work. Chris your site is superb! I’m only just starting to realize and utilize the power of CSS after been stuck using tables for years. The biggest problem I’m having is alignment, but I’m getting there thanks to sites like this.

    Menno van Slooten, I have bookmarked your site and I will explore it more when I do my rounds of exploring more of sites that I’ve bookmarked. :)

    Thanks!

    Jack

  73. MartinVr

    Hello, this is excellent work.

    How could I get href to work? I am a beginner in css and would really like to know what to do so that tabs would link to other html pages?
    Thanks

    Martin

    • MartinVr

      Hello, I found solution to my problem…I deleted ” e.preventDefault(); ” in javascript and now it works like a charm…

This comment thread is closed. If you have important information to share, you can always contact me.