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.
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.
Wow. Those are gorgeous!
This is really nice. Thanks for sharing.
But I have some problems. Can be because I try to use it together with
JQuery-Tabs.
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 ?
Awesome!!
Hey!
Very good technique, and this works perfectly in IE10 on W8!
Hey!
Seems to work fine on Opera 11 too ;)
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 !!!
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
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.
Beautiful :)
What about the tops of the interior tabs? the outside tabs look nice and rounded, but the interior is not as clean.
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:
You need to do this instead:
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
works just fine. There is no need to have four values for equally rounded corners.
I love it! The way you used all of these techniques is ingenious.
Sweet and clean. Thanks Chris.
Wow, these tabs are amazing. I guess I may _have_ to use them in upcoming projects! Thanks a lot!
WOW!
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!
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.
Hello
IE9 does support border-radius. The tabs look great!
You forgot to add border:
.tabrow li:before, .tabrow li:after { border: 1px solid #AAA; }
Great article, thanks!
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 :)
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
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.
Made the border change, thanks!
Nice!
niiice…
Use CSS3 Pie and you will have those rounded corners in IE.
http://css3pie.com/
great tutorial, thanks.
I would add one thing – in demo I would make entire area in tab clickable – not only text.
In the demo, they are.
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+.Re: entire area in tab clickable .
Move the padding from the .tabrow li {}
to
.tabrow a{color:#555;text-decoration:none; padding:2px 20px;}
Really nice, excelent work as always!
What a great effect. I’m sure I could use it on one or two of my sites.
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.
That shadow thing, to hide the corners? Love. It!
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.
wooww its so amazin’ its so clear
Aaah, good one.
At last! Thanks a lot for sharing, chris..
I love that fact that the demos are right there on the page!
not support IE :(
Pretty! It’s not just
border-radius
that keeps it from working in IE8, but alsobox-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.
Thanks Chris. This is really useful…
wow, gorgeous
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
Before and After Will not be there in javascript!!!
The author wrote this article keeping in mind to introduce “:AFTER” & “:BEFORE”… in HTML….
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!
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!
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.
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.
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.
Really great!
Tricky! :)
Great article!
i used the same concept ( self-developed ) on css summit ’11 for chris’ challenge – guess i’m not that original …
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!
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
oh sorry, ignore the post – didn’t uderstand your problem correctly, i guess :-P
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…
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
try this:
That’s fancy. Nice demo.
thanks chris ..
great tutorial ..
waiting for more tutorials ..
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.
Here’s an example of using :before and :after on a td:
http://jsfiddle.net/3zvHF/2/
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
This is a great technique! I wouldn’t have thought of this.
This is really nice. Thanks for sharing.
Two point of clarification, though. When you say:
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:
which is simply false. Try out:
on an input type=”radio”…
But it’s not compatibly with IE7 :) and you have some lib js for that’s?
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
If you use
<label>
tags and a group of radio buttons, you can perform the tab switching with no JavaScript whatsoever.Demo using jsFiddle
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?
@stryju
That’s awesome! Thank you very much for your help it works perfectly!
Regards,
cenco
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.
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!
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!
I’ve created a dabblet for this example:
http://dabblet.com/gist/1633247
so you can play around with css in the browser
Robin
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)Thanks for the tip there are some great articles on here!
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!
Nice and simple, thanks!
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.
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..
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
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
Hello, I found solution to my problem…I deleted ” e.preventDefault(); ” in javascript and now it works like a charm…
I have two questions:
Test Page: http://www.employeeuniversity.com/videos/customer-service-viral.htm
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
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!
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