Orman Clark’s Chunky 3D Web Buttons: The CSS3 Version
Tutorial Details
- Topic: CSS3
- Difficulty: Intermediate
- Estimated completion time: 30 mins
Today we’ll be making some awesome CSS3 buttons! They’re based on the popular PSD freebie Orman Clark made for his website Premium Pixels. We’ll try to make a CSS copy of them, as precisely and with as little HTML markup as possible.
Editor’s Note: Orman has sportingly allowed us to CSS-ify any of his Premium Pixel freebies that we choose. These chunky buttons are just one of the many freebies available, so expect more tutorials like this in the future. Huzzah!
Step 1: Outlining the HTML Document
We’ll start off by creating a new HTML document. I based mine on the HTML5 boilerplate, just to be able to start quickly and with the perfect document markup. I used the css normalization document that comes with it, too. Then we’ll add a list with some basic anchors in it. Simple as that, we don’t need any extra spans or divs, our good friend CSS3 will take care of that.
To be able to give it some css styles, we give the list a class ‘buttons’. And since we’re going to show all the colors Orman used in his design, we’ll give each link a different color as a class.
<ul class="buttons"> <li><a href="#" class="button gray">Download</a></li> <li><a href="#" class="button pink">Download</a></li> <li><a href="#" class="button blue">Download</a></li> <li><a href="#" class="button green">Download</a></li> <li><a href="#" class="button turquoise">Download</a></li> <li><a href="#" class="button black">Download</a></li> <li><a href="#" class="button darkgray">Download</a></li> <li><a href="#" class="button yellow">Download</a></li> <li><a href="#" class="button purple">Download</a></li> <li><a href="#" class="button darkblue">Download</a></li> </ul>
That’s all we need for now, our HTML document is done!
Here’s what it should look like when you view it in your browser so far:

Step 2: Some Basic CSS Styling
Before we start with styles like gradients, rounded corners etc., we’ll apply some basic styling first.
Nothing special here, just the usual CSS2 stuff.
ul { list-style: none; }
a.button {
display: block;
float: left;
position: relative;
height: 25px;
width: 80px;
margin: 0 10px 18px 0;
text-decoration: none;
font: 12px "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: bold;
line-height: 25px;
text-align: center;
}
We can easily alter the colors of the buttons too, since we added classes. So we’ll do that for every other color, for example gray. You can check all the color codes in the demo file.
/* GRAY */
.gray,
.gray:hover {
color: #555;
border-bottom: 4px solid #b2b1b1;
background: #eee;
}
.gray:hover { background: #e2e2e2; }
If you did everything well, you should have something like this. Which is nice.. if we were living in 2008!

Step 3: Double Borders all the Way!
Now, if you take a little closer look at the photoshop file, you’ll notice that there isn’t only a thicker border on the bottom, but also a thinner one all the way round, and a little extra line between the thick part and the actual border. To translate that last detail to css, we’ll be using a CSS2 trick, the :before and :after pseudo-elements.
We’ll position these elements – which we can see as separate boxes – exactly behind our actual button with the position property. To save some css lines, we’ll style both elements first and then add the values for the before-element only.
a.button {
display: block;
float: left;
position: relative;
height: 25px;
width: 80px;
margin: 0 10px 18px 0;
text-decoration: none;
font: 12px "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: bold;
line-height: 25px;
text-align: center;
}
a.button:before,
a.button:after {
content: '';
position: absolute;
left: -1px;
height: 25px;
width: 80px;
bottom: -1px;
}
a.button:before {
height: 23px;
bottom: -4px;
border-top: 0;
}
Things start looking good when we’re adding the right colors!
/* GRAY */
.gray,
.gray:hover {
color: #555;
border-bottom: 4px solid #b2b1b1;
background: #eee;
}
.gray:before,
.gray:after {
border: 1px solid #cbcbcb;
border-bottom: 1px solid #a5a5a5;
}
.gray:hover { background: #e2e2e2; }

Step 4: Adding CSS3 Magic
Now what you guys have all been waiting for, the CSS3 part. We’ll start by adding rounded corners to all our buttons:
a.button {
display: block;
float: left;
position: relative;
height: 25px;
width: 80px;
margin: 0 10px 18px 0;
text-decoration: none;
font: 12px "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: bold;
line-height: 25px;
text-align: center;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
And then of course our :before and :after elements need rounded corners too, to make the borders fit. However, the :before element doesn’t need the top corners to be rounded, otherwise we’ll see a little bug. Since the :before element is the one with the lowest position, we’ll add the box shadow to this element instead of to the main one.
a.button:before,
a.button:after {
content: '';
position: absolute;
left: -1px;
height: 25px;
width: 80px;
bottom: -1px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
a.button:before {
height: 23px;
bottom: -4px;
border-top: 0;
-webkit-border-radius: 0 0 3px 3px;
-moz-border-radius: 0 0 3px 3px;
border-radius: 0 0 3px 3px;
-webkit-box-shadow: 0 1px 1px 0px #bfbfbf;
-moz-box-shadow: 0 1px 1px 0px #bfbfbf;
box-shadow: 0 1px 1px 0px #bfbfbf;
}
Lastly we’ll apply some gradient backgrounds, an inner shadow and some text shadow for every separate color. We’ll add the :visited state too to prevent bugs in IE6.
/* GRAY */
a.gray,
a.gray:hover,
a.gray:visited {
color: #555;
border-bottom: 4px solid #b2b1b1;
text-shadow: 0px 1px 0px #fafafa;
background: #eee;
background: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#e2e2e2));
background: -moz-linear-gradient(top, #eee, #e2e2e2);
box-shadow: inset 1px 1px 0 #f5f5f5;
}
.gray:before,
.gray:after {
border: 1px solid #cbcbcb;
border-bottom: 1px solid #a5a5a5;
}
.gray:hover {
background: #e2e2e2;
background: -webkit-gradient(linear, left top, left bottom, from(#e2e2e2), to(#eee));
background: -moz-linear-gradient(top, #e2e2e2, #eee);
}
This should be our result. Lookin’ good, eh?

Step 5: Didn’t We Forget Something?
There’s one important thing we still need to do; Orman made a design for the active state too. So of course we will add that to our css version!
We’ll put the code for the active state under all our color definitions since some of these values need to be overwritten. The first difference with the other states is that it has no borders. It’s also positioned a bit lower to suggest indentation. And we’ll need to use 2 shadows instead of one: a normal, white one and a second, inner one that is transparent. Lastly, we don’t need the :before and :after pseudo-elements anymore.
/* ACTIVE STATE */
a.button:active {
border: none;
bottom: -4px;
margin-bottom: 22px;
-webkit-box-shadow: 0 1px 1px #fff;
-moz-box-shadow: 0 1px 1px #fff;
box-shadow: 1px 1px 0 #fff, inset 0 1px 1px rgba(0, 0, 0, 0.3);
}
a.button:active:before,
a.button:active:after {
border: none;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
This is what our buttons should look like in active state:

Step 6: (optional) Older Browsers
Now we have some nice CSS3 buttons that work in all modern browsers. But what about Internet Explorer, for example? IE8 and lower don’t support box or text shadow, nor gradients.
To be able to style our elements specifically for these browsers, we could use Modernizr, a javascript library that detects whether your browser can handle CSS3 and HTML5 properties. It does not fix older browsers’ issues, it adds classes to the html tag (reporting whichever capabilities are and aren’t available) to allow alternative styling.
Another option would be making these browsers behave with some other javascript libraries (those are called polyfills), but that’s something we’re not going to cover in this tutorial. Instead we’re just going to use an image for older browsers.
First we’ll make our custom build version of Modernizr, that way we don’t have to carry all the superfluous javascript with us. We can do that easily on their website. When we implemented the javascript in our html file, we just need to define the alternative styling for specific html classes. We’re going to use an image for browsers that don’t support (one of) the 2 most notable CSS3 effects we used, border radius and css gradients. And since some older browsers don’t even support generated content (:before and :after), we’ll mention that one too.
/* MODERNIZR FALLBACK */
.no-cssgradients a.button, .no-cssgradients a.button:visited,
.no-borderradius a.button, .no-borderradius a.button:visited,
.no-generatedcontent a.button, .no-generatedcontent a.button:visited {
background: url(images/sprite.png) no-repeat 0 0px;
height: 32px;
width: 82px;
}
.no-cssgradients a.button:hover,
.no-borderradius a.button:hover,
.no-generatedcontent a.button:hover {
background: url(images/sprite.png) no-repeat 0 -32px;
}
.no-cssgradients a.button:active,
.no-borderradius a.button:active,
.no-generatedcontent a.button:active {
background: url(images/sprite.png) no-repeat 0 -64px;
bottom: 0;
line-height: 35px;
}
.no-cssgradients a.gray,
.no-cssgradients a.gray:visited,
.no-cssgradients a.gray:hover { background-position-x: 0; }
.no-cssgradients a.pink,
.no-cssgradients a.pink:visited,
.no-cssgradients a.pink:hover { background-position-x: -82px; }
.no-cssgradients a.blue,
.no-cssgradients a.blue:visited,
.no-cssgradients a.blue:hover { background-position-x: -164px; }
.no-cssgradients a.green,,
.no-cssgradients a.green:visited,
.no-cssgradients a.green:hover { background-position-x: -246px; }
.no-cssgradients a.turquoise,
.no-cssgradients a.turquoise:visited,
.no-cssgradients a.turquoise:hover { background-position-x: -328px; }
.no-cssgradients a.black,
.no-cssgradients a.black:visited,
.no-cssgradients a.black:hover { background-position-x: -410px; }
.no-cssgradients a.darkgray,
.no-cssgradients a.darkgray:visited,
.no-cssgradients a.darkgray:hover { background-position-x: -492px; }
.no-cssgradients a.yellow,
.no-cssgradients a.yellow:visited,
.no-cssgradients a.yellow:hover { background-position-x: -574px; }
.no-cssgradients a.purple,
.no-cssgradients a.purple:visited,
.no-cssgradients a.purple:hover { background-position-x: -656px; }
.no-cssgradients a.darkblue,
.no-cssgradients a.darkblue:visited,
.no-cssgradients a.darkblue:hover { background-position-x: -738px; }
.no-cssgradients a.button, .no-cssgradients a.button:visited, .no-cssgradients a.button:hover, .no-cssgradients a.button:before, .no-cssgradients a.button:after,
.no-borderradius a.button, .no-borderradius a.button:visited, .no-borderradius a.button:hover, .no-borderradius a.button:before, .no-borderradius a.button:after,
.no-generatedcontent a.button, .no-generatedcontent a.button:visited, .no-generatedcontent a.button:hover, .no-generatedcontent a.button:before, .no-generatedcontent a.button:after {
border: 0;
}
To improve performance, we use a CSS Sprite for the hover and active state. And the :visited state is still included to prevent the IE6 bug.
Conclusion
So, now we have our fully cross-browser CSS3 buttons! You’ll probably think that this looks like a lot of code for 10 buttons, but of course this is only a demonstration of what you can or can’t do with CSS3. You’re free to do whatever you want with it!
So far my very first tutorial.. I hope you liked it, thanks for reading!
Very nice tutorial – a little simple, but really nicely laid out!
Nice work. Clearly explained, will be using this in the future
Neat ‘n simple. Just the way I like it :) thanks for the inspiration.
Gorgeous!
Well.. This example is far better http://dimox.name/examples/beautiful-3d-buttons-using-css3/ (not mine)
Thanks for the link – I loved the tutorial above, but your link just makes things easier! Bookmarked.
Very well done, and thankfully not another cumbersome video or multimedia tutorial. Basic foundation upon which to easily expand, and that shows you know how to help all of us. Thank you!
Much as this is classified as intermediate, I think there are many beginners who could follow it by starting with those initial first steps while looking at the download source at the same time.
I think the box shadow should something like(For the lighter grey one):-
box-shodwo:0 1px 0 #F7F7F7 inset, 1px 0 0 #EEEEEE inset, 1px 0 0 #EEEEEE inset;
Coz orman has used inset shadow on both left and right side of the buttons,but this shadow is a bit darker then the top inset shodow
But in the above example Lukas you have inserted shadow only on the left side of the button.
I think its not the exact match
What is the license file? Can I use these buttons in my ThemeForest project?
Technically speaking, you can take away any techniques that you learn using Tuts+ tutorials, and use them for whatever purposes you please.
Being a fan of Clark’s pixel perfection, I was pleased to go through this tutorial and learn a bit more about using pseudo-elements to acheive such pleasing effects.
However there’s a bit of an issue here, if anyone can help:
You always need to set the pseudo-elements width (in pixels) in order for them to wrap around the button, right? If so, this prevents this technique from being used with dynamic text, as you always need to know the exact width of the button itself. How to overcome this?
Thank you for the tutorial!
That’s a good point Ricardo, I should have spotted that.
You can easily have the buttons adjust to the text contained within them. First, alter the width and height of the pseudo elements (:before and :after) to
100%. They will then equal the dimensions of their parent element, thea.Of course, the
astill has a fixed width and height, so remove them. Then, add some padding to the left and right of thea– whatever you wantpadding: 0 10px;for example.That’s it! You’ll then be able to add longer strings of text, and even throw in line-breaks for multiple lines.
The only issue with this is the fallback technique, which uses images as backgrounds. They of course can’t alter dimensions. This means you’ll be covered for all modern browsers, but IE6 + IE7 won’t be coming to the party.. Hope that helps though :)
Great Tuts dude, I was searching like this for long time & i found this…..
Great job man, gotta love the CSS3 !
Nice, I saw this style on a couple sites just randomly browsing the internet. It’s spreading fast. :)
Thanks, I love the CSS3 3D buttons, especially when they’re animated. :)
Great tut, but the buttons don’t work well on chrome, they look completely different than on FF
Buttons in Chrome do look strange! Any Solution for that problem?
Removing
-webkit-border-radius: 3px;
border-radius: 3px;
from a.button
fixes this problem in Chrome.