Grow your CSS skills. Land your dream job.

Tabs with Round Out Borders

Published by Chris Coyier

Rounded corners are now trivially easy to achieve via border-radius. But that only allows us to cut into the shape. What if we want to connect a shape to another with a rounded outward corner. Much easier to explain with a graphic:


The top corners are easy, just border-radius. The bottom corners, less easy.
View Demo   Download Files

Clean HTML

Of course, on the web, just about anything visual is possible. Worst-case-scenario you can use images. Our goal here, as ever, is to use no images (quick! accessible! easy to update!) and use completely clean semantic HTML (quick! accessible! easy to update!). So here's the markup:

<ul class="tabs group">
  <li class="active"><a href="#one">One</a></li> 
  <li><a href="#two">Two</a></li> 
  <li><a href="#three">Three</a></li>
  <li><a href="#three">Four</a></li> 
</ul>

A class of active indicates which tab reflects the current page.

How this is going down

The reason this is tricky is that we need a shape to stick out of the tab element. To get this done while keeping our markup clean, we'll use pseudo elements. If you need a refresher, you can learn about them here and here. Essentially, they can add extra elements to the page that we can style, directly through CSS. Every element can have two - :before and :after. Ultimately we'll be using four per tab, which is possible because each tab is make from two elements, the list item and the anchor link.

Let's visualize this step by step, without looking out any code just yet.

1) Natural State


List items are naturally block level and anchor links are inline, so the layout is like this.

2) Float


By floating the list items to the left, the list items will line up next to each other and shrink to the size of the anchor links inside them.

3) Same Size


The list items themselves have no margin or padding, so really the list items and anchor links are the exact same size, directly on top of each other.

4) Just one


Let's focus on just one of them...

5) Circles


We'll use two of our four available pseudo elements to place circles on the bottom left and bottom right of the tab.

6) Squares


With the other two pseudo elements we'll make smaller squares.

7) Colorize the tab and content


The "active" tab and the content will share the same background color.

8) Colorize the pseudo elements


The squares match the color of the active tab, the circles match the background behind them.

9) Stacking


With z-index, we'll make sure the circle sits on top and cuts off the color of the square.

10) No borders


The borders were just for illustration, really it would look more like this.

11) Finishing


Add the same concept to the outer tabs and round the tops with border-radius and it's done!

CSS

This is a big ass block of CSS, but I've tried to comment it up so that each part makes sense.

.tabs li { 
  /* Makes a horizontal row */
  float: left; 
	
  /* So the psueudo elements can be
     abs. positioned inside */
  position: relative; 
}
.tabs a { 
  /* Make them block level
     and only as wide as they need */
  float: left; 
  padding: 10px 40px; 
  text-decoration: none;
  
  /* Default colors */ 
  color: black;
  background: #ddc385; 
  
  /* Only round the top corners */
  -webkit-border-top-left-radius: 15px;
  -webkit-border-top-right-radius: 15px;
  -moz-border-radius-topleft: 15px;
  -moz-border-radius-topright: 15px;
  border-top-left-radius: 15px;
  border-top-right-radius: 15px; 
}
.tabs .active {
  /* Highest, active tab is on top */
  z-index: 3;
}
.tabs .active a { 
  /* Colors when tab is active */
  background: white; 
  color: black; 
}
.tabs li:before, .tabs li:after, 
.tabs li a:before, .tabs li a:after {
  /* All pseudo elements are 
     abs. positioned and on bottom */
  position: absolute;
  bottom: 0;
}
/* Only the first, last, and active
   tabs need pseudo elements at all */
.tabs li:last-child:after,   .tabs li:last-child a:after,
.tabs li:first-child:before, .tabs li:first-child a:before,
.tabs .active:after,   .tabs .active:before, 
.tabs .active a:after, .tabs .active a:before {
  content: "";
}
.tabs .active:before, .tabs .active:after {
  background: white; 
  
  /* Squares below circles */
  z-index: 1;
}
/* Squares */
.tabs li:before, .tabs li:after {
  background: #ddc385;
  width: 10px;
  height: 10px;
}
.tabs li:before {
  left: -10px;      
}
.tabs li:after { 
  right: -10px;
}
/* Circles */
.tabs li a:after, .tabs li a:before {
  width: 20px; 
  height: 20px;
  /* Circles are circular */
  -webkit-border-radius: 10px;
  -moz-border-radius:    10px;
  border-radius:         10px;
  background: #222;
  
  /* Circles over squares */
  z-index: 2;
}
.tabs .active a:after, .tabs .active a:before {
  background: #ddc385;
}
/* First and last tabs have different
   outside color needs */
.tabs li:first-child.active a:before,
.tabs li:last-child.active a:after {
  background: #222;
}
.tabs li a:before {
  left: -20px;
}
.tabs li a:after {
  right: -20px;
}

That's that!

View Demo   Download Files

Should work in just about any decent browser and also IE 9 and up. Should also fall back fine (just no round-outs) in older browsers.

Steve Smith Method

About the exact time as I was creating this to include in a talk I was doing about pseudo elements. Steve Smith of Ordered List published a very similar method. Steve's method has borders around the tabs, mine has tabs butted up against each other. Both cool if you ask me.

Comments

  1. Maikel
    Permalink to comment#

    Epic! I’ll definitely use this.

  2. aihowes
    Permalink to comment#

    Great stuff Chris!

  3. woww, nice . .
    good job,
    I like 6th – 9th steps, you have a great idea ;)

  4. Johnathan
    Permalink to comment#

    Amazing

  5. It’s too bad we can’t use a negative border-radius. If we could, we could do this with just two pseudo elements per tab, and less code to conditionally change background colors.

    • Wouldn’t a negative border radius produce ticket corners? example

    • If there were many forms of border-radius (ticketed, the normal one, the one illustrated here etc. then there’d be a lot more choice of border-radii to choose from, although I know it’s impractical, it’s fun to think about.

      BTW, Chris, I think I saw this somewhere, but this kinda explanation is only found at your website, great job! Fantastic! It is truly said, a picture is worth a thousand words.

  6. Permalink to comment#

    Nice work Chris, I was actually trying to find this exact type of tabbed navigation the other night.

    • madhu
      Permalink to comment#

      i have doubt in css — html file in folder css style sheet is out side how can i apply styles for html page

  7. Permalink to comment#

    This is some seriously awesome CSS. Always a fan of your work!

  8. J
    Permalink to comment#

    Why not just round the bottom corners of the “inactive” tabs next to the active tab?

    • Lol wow, that’s really clever! I’m embarrassed I didn’t think of that.

    • In the example above, they would be black. Wouldn’t they? I don’t know what you’d do about the first and last tab, you might need an extra trick just for them, in which case it might be simpler to just use a consistent approach for each tab.

    • @Lee,

      Since coloring the background of the ul tag would mess up the rounded corners at the tops of the tabs, maybe you could give the ul tag an :after psudo element, make it the same height as the bottom border radius, give it the same color as the active tab and position it at the bottom of the ul with the right z-index? It actually feels a little more hacky to me and a little less elegant that way, but it would use less css.

  9. Archi
    Permalink to comment#

    Really smarter way of thinking…! Loved it

  10. Permalink to comment#

    It looks really nice!

  11. Good tip Chris keep it up…

  12. Tinny
    Permalink to comment#

    Nice one.
    I would add an outline:none to avoid outlined tabs in IE when clicked.

  13. This was a nice one Cris!

  14. Permalink to comment#

    hey, what do you know? a css trick!
    this one deserved the lengthy explanation though, seeing how fast you explained it at WordCamp SF :)

  15. Very nice. Leaving my appreciation for how much work went into this post; it would have been much easier to dump the code here, instead of going through a visual step-by-step explanation. Love the spirit here at CSS Tricks.

    • I couldn’t agree with you more, Melanie! I too appreciate the added visuals to help us better understand how the CSS works. Thanks for this post, Chris!

  16. Outstanding.

  17. Wow, really nice Chris.

    I think I remember seeing a post on this a while back or at least something similar. It was fun too look through again too – amazing what a little creativity and CSS3 can do :P

  18. Permalink to comment#

    This may be a dumb question, but can you use a background image on the squares (the pseudo-elements). I ask because well, I would like to use it but stacked against a background header…..

  19. nice one
    definitely have to read through the code :]

  20. Emily
    Permalink to comment#

    These look great, thanks for the tip :)
    The only thing that bugs me a little is that you can’t click on the tab where the adjacent one’s square and circle element is. I suppose this isn’t a big deal when there is no hover state on the tabs but I think with one it would become more annoying with one?

  21. Mike Fielden
    Permalink to comment#

    I really liked this particular way of illustrating what exactly your thought process was… More like this please :)

  22. Ben
    Permalink to comment#

    This is a great technique but unfortunately kind of hinges on using solid colors. Tried to do this once on a project but couldn’t because the active tab was on top of a gradient, which would make the circle pseudo-element visible.

    • Permalink to comment#

      But I just asked if you could use a bg-image and Chris said yes. I guess you could use the gradient as one?

    • Ben
      Permalink to comment#

      This technique works because the circle pseudo-elements are the same as what’s behind them, making them appear as part of the “negative” space (positive being the tab), so it all depends on if you can make the circles appear as though they’re part of the background. With non-solid backgrounds I don’t see how this would be possible.

  23. That’s a great idea but the circles and squares you add link to their parent element not the link they are placed over. It basically takes away a clickable area of the current links neighbors.

  24. Max Henchman
    Permalink to comment#

    Very cool trick! I’m going to try it with an image and probably fail.

  25. Rachid
    Permalink to comment#

    Great job This work only in Firefox Browser. any Idea ?

  26. Josh
    Permalink to comment#

    I agree with John and Emily: this isn’t a very good technique to use because you can basically hover over “Two” and still get the link for “One.”

    Using this technique, however nice it may be, will end up sending your users to the wrong page at some point. You should not sacrifice usability for some fancy corners.

    If you’re going to use them this way, I’d suggest putting some margin on the li elements, so that your links don’t overlap.

  27. Permalink to comment#

    Awesome post Chris, thanks for your work.

  28. Permalink to comment#

    Interesting technique, but I’d love to know how computationally expensive it it’s for the browser to create these pseudo-elements vs the http hit of using a single background-image for the tabs using sliding doors with a sprite.

  29. Permalink to comment#

    Excellent! Simplicity, and boldness all within a five minute creation. I love how simple & effective this idea is. Great share.

  30. Permalink to comment#

    Given Demo not working in ie6

    • Alex W
      Permalink to comment#

      Why would something posted in 2011 be concerned with IE6? That browser is completely outdated. Web designers need to continue to move on with newer, better things. Plus, IE6 has dropped below 10% market share so most have dropped support for it, thankfully.

  31. Permalink to comment#

    Hi.
    I translate your article in russian and add better fallback for ie6, ie7 and ie8. http://habrahabr.ru/blogs/webdev/128210/ —translation.
    http://websaints.net/example/roundouttabsmagic/index.html — fallback example.

  32. S_gonzales
    Permalink to comment#

    Any way to do this without disabling the click on the the corner of the tab? (where is actually a circle with the same color as in the other tab?)

    i kindof consider that a small glitch, that would make a potential client buzz in my ears.

  33. Moiz Raja
    Permalink to comment#

    Great technique and wonderful step by step explanation of how the trick works. You should write a book :)

    • Alex W
      Permalink to comment#

      A book would be great if it was as quality as all your tips, tricks, and demos!

  34. Permalink to comment#

    Great technique and tutorial.

    @Rachid : it works with Google Chrome and Opera too !!

  35. Permalink to comment#

    Just to be extra clear for people who might not know. This will not work in Internet Explorer 8 and under because of lack of support for border-radius and/or :before/:after pseudo-elements.

    IE8 supports pseudo-elements but not border-radius, but you could use a polyfill such as CSS3PIE to work around that.

    Then if you’re using CSS3PIE for IE8 then you may as well polyfill IE7′s lack of pseudo-element support with Dean Edwards IE8.js script.

    That means you can get this example working in IE6/7/8 with the help of some JavaScript polyfills.

  36. Karl
    Permalink to comment#

    This may sound like a stupid NooB question, but is it can this be made to work with a hover/rollover state?

  37. Karl
    Permalink to comment#

    This may sound like a stupid NooB question, but can this be made to work with a hover/rollover state?

  38. Very nice article Chris, with a really good easy to follow step-by-step guide.
    I would just like to propose a small change…

    you don’t really need the squares if you use the circleshaped div’s bottom and right borders combined with a rotation of 45 degrees:
    -webkit-transform: rotate(45deg);
    -moz-transform: rotate(45deg);
    -ms-transform: rotate(45deg);
    -o-transform: rotate(45deg);
    If you first declare the circle and it’s borders transparent, and than add a line in which you adres only the bottom-border of the right circle and the bottom-right of the left circle color to be white, than you would only need to position the circles so that their 1/4 piece of border falls into place with the rest.

    I refer to one of the tricks mentioned here: http://css-tricks.com/examples/ShapesOfCSS/
    But thanks for the nice article!
    And may you all have a mostly pure html / css 2014! ;)

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