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:
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
2) Float
3) Same Size
4) Just one
5) Circles
6) Squares
7) Colorize the tab and content
8) Colorize the pseudo elements
9) Stacking
10) No borders
11) Finishing
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!
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.
Epic! I’ll definitely use this.
Great stuff Chris!
woww, nice . .
good job,
I like 6th – 9th steps, you have a great idea ;)
Amazing
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.
Nice work Chris, I was actually trying to find this exact type of tabbed navigation the other night.
i have doubt in css — html file in folder css style sheet is out side how can i apply styles for html page
This is some seriously awesome CSS. Always a fan of your work!
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.
Really smarter way of thinking…! Loved it
It looks really nice!
Good tip Chris keep it up…
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.
This was a nice one Cris!
hey, what do you know? a css trick!
this one deserved the lengthy explanation though, seeing how fast you explained it at WordCamp SF :)
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!
Outstanding.
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
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…..
yes.
nice one
definitely have to read through the code :]
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?
I really liked this particular way of illustrating what exactly your thought process was… More like this please :)
+++ would read again
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.
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.
Very cool trick! I’m going to try it with an image and probably fail.
Great job This work only in Firefox Browser. any Idea ?
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.
Slap some pointer-events on your pseudo-elements and you’re all set. https://css-tricks.com/6379-pointer-events-current-nav/ – Tried it in Firebug on the demo and it worked great.
Awesome post Chris, thanks for your work.
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.
Excellent! Simplicity, and boldness all within a five minute creation. I love how simple & effective this idea is. Great share.
Given Demo not working in ie6
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.
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.
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.
pointer-events – https://css-tricks.com/6379-pointer-events-current-nav/
Great technique and wonderful step by step explanation of how the trick works. You should write a book :)
A book would be great if it was as quality as all your tips, tricks, and demos!
Great technique and tutorial.
@Rachid : it works with Google Chrome and Opera too !!
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.
This may sound like a stupid NooB question, but is it can this be made to work with a hover/rollover state?
This may sound like a stupid NooB question, but can this be made to work with a hover/rollover state?
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: https://css-tricks.com/examples/ShapesOfCSS/
But thanks for the nice article!
And may you all have a mostly pure html / css 2014! ;)