Tabs with Round Out Borders

Sep 4 2011
53

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.

Subscribe to The Thread

  1. Maikel

    Epic! I’ll definitely use this.

  2. aihowes

    Great stuff Chris!

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

  4. Johnathan

    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. Nice work Chris, I was actually trying to find this exact type of tabbed navigation the other night.

    • madhu

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

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

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

    Really smarter way of thinking…! Loved it

  10. It looks really nice!

  11. Good tip Chris keep it up…

  12. Tinny

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

    • Please stop doing this, people. Seeing those “ugly” focus indicators is actually important.

  13. This was a nice one Cris!

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

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

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

  19. Emily

    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?

  20. Mike Fielden

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

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

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

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

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

  23. Max Henchman

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

  24. Rachid

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

  25. Josh

    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.

  26. Awesome post Chris, thanks for your work.

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

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

  29. Given Demo not working in ie6

    • Alex W

      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.

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

  31. S_gonzales

    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.

  32. Moiz Raja

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

    • Alex W

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

  33. Great technique and tutorial.

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

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

  35. Karl

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

  36. Karl

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

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