Grow your CSS skills. Land your dream job.

(Better) Tabs with Round Out Borders

Published by Chris Coyier

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 class="selected">Sit amet</li>
    <li>Consectetur adipisicing</li>

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.

Update: Allan Watkins sent me a variation of these that point downwards:


  1. Permalink to comment#

    Wow. Those are gorgeous!

    • Bernd

      This is really nice. Thanks for sharing.

      But I have some problems. Can be because I try to use it together with
      If I click on a tab outside the link area, than I get optical changes, but it will
      not change the tabsheet.
      If I click on a tab inside the link area, than it will changed the tabsheet, but I loose the optical changes.

      Everybody has a tip for me ?

  2. Nick
    Permalink to comment#


  3. Permalink to comment#

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

  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
      Permalink to comment#

      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.

    • Kevin
      Permalink to comment#

      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. J
    Permalink to comment#

    Beautiful :)

  6. theTimmy
    Permalink to comment#

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

  7. Rafael
    Permalink to comment#

    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;
    • Permalink to comment#

      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 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.

    • Ana
      Permalink to comment#

      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. Permalink to comment#

    Sweet and clean. Thanks Chris.

  10. Permalink to comment#

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

  11. Liz
    Permalink to comment#


  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. Permalink to comment#

    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
    Permalink to comment#


  15. Dave
    Permalink to comment#

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

  16. Maurycy
    Permalink to comment#

    You forgot to add border:

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

    Great article, thanks!

  17. Tom
    Permalink to comment#

    Great Tutorial. Used it to make trapeze shaped tabs as the ones Google Chrome uses and this is my result:

    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
    Permalink to comment#


  21. Permalink to comment#


  22. Adam Phin
    Permalink to comment#

    Use CSS3 Pie and you will have those rounded corners in IE.

  23. great tutorial, thanks.

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

  24. Permalink to comment#

    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!!!


    • Ana
      Permalink to comment#

      For Firefox 3.6 the -moz- prefix is required.

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

    • Martyyyy
      Permalink to comment#

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

  25. Asgaroth
    Permalink to comment#

    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. Permalink to comment#

    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
    Permalink to comment#

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

  29. Permalink to comment#

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

  30. wooww its so amazin’ its so clear

  31. Andy
    Permalink to comment#

    Aaah, good one.

  32. Permalink to comment#

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

  33. charbs
    Permalink to comment#

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

  34. saeed
    Permalink to comment#

    not support IE :(

  35. T.J. Crowder
    Permalink to comment#

    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.

    • Permalink to comment#

      Try using CSS3 PIE:

      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 script and you will need to use the PIE.php script to load it.

  36. Thanks Chris. This is really useful…

  37. Permalink to comment#

    wow, gorgeous

  38. Kim Christiansen
    Permalink to comment#

    The first and last pseudo classes can be used in IE 6-8 with the polyfill Selectivizr:

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

    • yashu
      Permalink to comment#

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

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

  39. Permalink to comment#

    Impressive! I tried to complete the same effect last week but I used 3 pseudo-element: 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. Permalink to comment#

    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. Permalink to comment#

    Really great!

  45. Permalink to comment#

    Tricky! :)
    Great article!

  46. stryju
    Permalink to comment#

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

  47. illufox
    Permalink to comment#

    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
      Permalink to comment#

      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
      Permalink to comment#

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

  48. Permalink to comment#

    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.

  49. Permalink to comment#


    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!


    • stryju
      Permalink to comment#

      try this:

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

  51. Sultan
    Permalink to comment#

    thanks chris ..

    great tutorial ..

    waiting for more tutorials ..

  52. MikeR
    Permalink to comment#

    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. Permalink to comment#

    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. Ben
    Permalink to comment#

    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:

    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. Permalink to comment#

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

  57. Permalink to comment#

    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. Ira Hanson
    Permalink to comment#

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

    Demo using jsFiddle

  59. wobla
    Permalink to comment#

    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?

  60. Permalink to comment#


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



  61. Brad
    Permalink to comment#

    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!

    • Permalink to comment#

      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
      Permalink to comment#

      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.

    • Permalink to comment#

      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!

  62. Permalink to comment#

    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!

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

    so you can play around with css in the browser


  64. 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)

  65. Permalink to comment#

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

  66. herbyderby
    Permalink to comment#

    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!

  67. Will Drotar
    Permalink to comment#

    Nice and simple, thanks!

  68. Permalink to comment#

    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.

  69. Kake
    Permalink to comment#


    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..

  70. Permalink to comment#

    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. :)



  71. MartinVr
    Permalink to comment#

    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?


    • MartinVr
      Permalink to comment#

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

  72. Darin
    Permalink to comment#

    I have two questions:

    Test Page:

    When i pull this test page up, the tabs are not formatted. Not of the shape is there and the tab content boxes are all messed up as well. It looks fine in Chrome, and IE8 (shape is there at least), and in IE10, but in IE9 I have to click the COMPATIBILITY VIEW button to get the tabs to “shape up” and do their thing. What could be causing that?
    What do I need to put in the CSS to have the active tab (the one that is viewed when you load the page) to show as a white tab, as they look like wh4en you’ve clicked on a tab.

    Thanks in advance – the IE9 issue is mission critical

  73. Permalink to comment#

    The tabs look slightly broken to me, both under Firefox and Chromium. If you set “-5px” instead of “-6px” on the pseudo-elements, they look perfect!

  74. Bernd

    Now, I have created a version, that works with JQuery-Tabs perfectly.

    Do you have a tip for me to aligne it from center to left side, so it do not loose the borders on the left side (padding or margin parameters) ?

    Many tanks from Germany

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

*May or may not contain any actual "CSS" or "Tricks".