(Better) Tabs with Round Out Borders

Avatar of Chris Coyier
Chris Coyier on (Updated on )

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: linear-gradient(to bottom, #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:

See the Pen Round Out Tabs that Point Down by Chris Coyier (@chriscoyier) on CodePen.