Orman Clark's Chunky 3D Web Buttons: The CSS3 Version
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.
1 |
<ul class="buttons"> |
2 |
<li><a href="#" class="button gray">Download</a></li> |
3 |
<li><a href="#" class="button pink">Download</a></li> |
4 |
<li><a href="#" class="button blue">Download</a></li> |
5 |
<li><a href="#" class="button green">Download</a></li> |
6 |
<li><a href="#" class="button turquoise">Download</a></li> |
7 |
<li><a href="#" class="button black">Download</a></li> |
8 |
<li><a href="#" class="button darkgray">Download</a></li> |
9 |
<li><a href="#" class="button yellow">Download</a></li> |
10 |
<li><a href="#" class="button purple">Download</a></li> |
11 |
<li><a href="#" class="button darkblue">Download</a></li> |
12 |
</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.
1 |
ul { list-style: none; } |
2 |
|
3 |
a.button { |
4 |
display: block; |
5 |
float: left; |
6 |
position: relative; |
7 |
height: 25px; |
8 |
width: 80px; |
9 |
margin: 0 10px 18px 0; |
10 |
|
11 |
text-decoration: none; |
12 |
font: 12px "Helvetica Neue", Helvetica, Arial, sans-serif; |
13 |
font-weight: bold; |
14 |
line-height: 25px; |
15 |
text-align: center; |
16 |
}
|
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.
1 |
/* GRAY */
|
2 |
.gray, |
3 |
.gray:hover { |
4 |
color: #555; |
5 |
border-bottom: 4px solid #b2b1b1; |
6 |
background: #eee; |
7 |
}
|
8 |
|
9 |
.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.
1 |
a.button { |
2 |
display: block; |
3 |
float: left; |
4 |
position: relative; |
5 |
height: 25px; |
6 |
width: 80px; |
7 |
margin: 0 10px 18px 0; |
8 |
|
9 |
text-decoration: none; |
10 |
font: 12px "Helvetica Neue", Helvetica, Arial, sans-serif; |
11 |
font-weight: bold; |
12 |
line-height: 25px; |
13 |
text-align: center; |
14 |
}
|
15 |
|
16 |
a.button:before, |
17 |
a.button:after { |
18 |
content: ''; |
19 |
position: absolute; |
20 |
left: -1px; |
21 |
height: 25px; |
22 |
width: 80px; |
23 |
bottom: -1px; |
24 |
}
|
25 |
|
26 |
a.button:before { |
27 |
height: 23px; |
28 |
bottom: -4px; |
29 |
border-top: 0; |
30 |
}
|
Things start looking good when we're adding the right colors!
1 |
/* GRAY */
|
2 |
.gray, |
3 |
.gray:hover { |
4 |
color: #555; |
5 |
border-bottom: 4px solid #b2b1b1; |
6 |
background: #eee; |
7 |
}
|
8 |
|
9 |
.gray:before, |
10 |
.gray:after { |
11 |
border: 1px solid #cbcbcb; |
12 |
border-bottom: 1px solid #a5a5a5; |
13 |
}
|
14 |
|
15 |
.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:
1 |
a.button { |
2 |
display: block; |
3 |
float: left; |
4 |
position: relative; |
5 |
height: 25px; |
6 |
width: 80px; |
7 |
margin: 0 10px 18px 0; |
8 |
|
9 |
text-decoration: none; |
10 |
font: 12px "Helvetica Neue", Helvetica, Arial, sans-serif; |
11 |
font-weight: bold; |
12 |
line-height: 25px; |
13 |
text-align: center; |
14 |
|
15 |
-webkit-border-radius: 3px; |
16 |
-moz-border-radius: 3px; |
17 |
border-radius: 3px; |
18 |
}
|
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.
1 |
a.button:before, |
2 |
a.button:after { |
3 |
content: ''; |
4 |
position: absolute; |
5 |
left: -1px; |
6 |
height: 25px; |
7 |
width: 80px; |
8 |
bottom: -1px; |
9 |
|
10 |
-webkit-border-radius: 3px; |
11 |
-moz-border-radius: 3px; |
12 |
border-radius: 3px; |
13 |
}
|
14 |
|
15 |
a.button:before { |
16 |
height: 23px; |
17 |
bottom: -4px; |
18 |
border-top: 0; |
19 |
|
20 |
-webkit-border-radius: 0 0 3px 3px; |
21 |
-moz-border-radius: 0 0 3px 3px; |
22 |
border-radius: 0 0 3px 3px; |
23 |
|
24 |
-webkit-box-shadow: 0 1px 1px 0px #bfbfbf; |
25 |
-moz-box-shadow: 0 1px 1px 0px #bfbfbf; |
26 |
box-shadow: 0 1px 1px 0px #bfbfbf; |
27 |
}
|
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.
1 |
/* GRAY */
|
2 |
a.gray, |
3 |
a.gray:hover, |
4 |
a.gray:visited { |
5 |
color: #555; |
6 |
border-bottom: 4px solid #b2b1b1; |
7 |
text-shadow: 0px 1px 0px #fafafa; |
8 |
|
9 |
background: #eee; |
10 |
background: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#e2e2e2)); |
11 |
background: -moz-linear-gradient(top, #eee, #e2e2e2); |
12 |
|
13 |
box-shadow: inset 1px 1px 0 #f5f5f5; |
14 |
}
|
15 |
|
16 |
.gray:before, |
17 |
.gray:after { |
18 |
border: 1px solid #cbcbcb; |
19 |
border-bottom: 1px solid #a5a5a5; |
20 |
}
|
21 |
|
22 |
.gray:hover { |
23 |
background: #e2e2e2; |
24 |
background: -webkit-gradient(linear, left top, left bottom, from(#e2e2e2), to(#eee)); |
25 |
background: -moz-linear-gradient(top, #e2e2e2, #eee); |
26 |
}
|
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.
1 |
/* ACTIVE STATE */
|
2 |
a.button:active { |
3 |
border: none; |
4 |
bottom: -4px; |
5 |
margin-bottom: 22px; |
6 |
|
7 |
-webkit-box-shadow: 0 1px 1px #fff; |
8 |
-moz-box-shadow: 0 1px 1px #fff; |
9 |
box-shadow: 1px 1px 0 #fff, inset 0 1px 1px rgba(0, 0, 0, 0.3); |
10 |
}
|
11 |
|
12 |
a.button:active:before, |
13 |
a.button:active:after { |
14 |
border: none; |
15 |
|
16 |
-webkit-box-shadow: none; |
17 |
-moz-box-shadow: none; |
18 |
box-shadow: none; |
19 |
}
|
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.
1 |
/* MODERNIZR FALLBACK */
|
2 |
.no-cssgradients a.button, .no-cssgradients a.button:visited, |
3 |
.no-borderradius a.button, .no-borderradius a.button:visited, |
4 |
.no-generatedcontent a.button, .no-generatedcontent a.button:visited { |
5 |
background: url(images/sprite.png) no-repeat 0 0px; |
6 |
height: 32px; |
7 |
width: 82px; |
8 |
}
|
9 |
|
10 |
.no-cssgradients a.button:hover, |
11 |
.no-borderradius a.button:hover, |
12 |
.no-generatedcontent a.button:hover { |
13 |
background: url(images/sprite.png) no-repeat 0 -32px; |
14 |
}
|
15 |
|
16 |
.no-cssgradients a.button:active, |
17 |
.no-borderradius a.button:active, |
18 |
.no-generatedcontent a.button:active { |
19 |
background: url(images/sprite.png) no-repeat 0 -64px; |
20 |
bottom: 0; |
21 |
line-height: 35px; |
22 |
}
|
23 |
|
24 |
.no-cssgradients a.gray, |
25 |
.no-cssgradients a.gray:visited, |
26 |
.no-cssgradients a.gray:hover { background-position-x: 0; } |
27 |
|
28 |
.no-cssgradients a.pink, |
29 |
.no-cssgradients a.pink:visited, |
30 |
.no-cssgradients a.pink:hover { background-position-x: -82px; } |
31 |
|
32 |
.no-cssgradients a.blue, |
33 |
.no-cssgradients a.blue:visited, |
34 |
.no-cssgradients a.blue:hover { background-position-x: -164px; } |
35 |
|
36 |
.no-cssgradients a.green,, |
37 |
.no-cssgradients a.green:visited, |
38 |
.no-cssgradients a.green:hover { background-position-x: -246px; } |
39 |
|
40 |
.no-cssgradients a.turquoise, |
41 |
.no-cssgradients a.turquoise:visited, |
42 |
.no-cssgradients a.turquoise:hover { background-position-x: -328px; } |
43 |
|
44 |
.no-cssgradients a.black, |
45 |
.no-cssgradients a.black:visited, |
46 |
.no-cssgradients a.black:hover { background-position-x: -410px; } |
47 |
|
48 |
.no-cssgradients a.darkgray, |
49 |
.no-cssgradients a.darkgray:visited, |
50 |
.no-cssgradients a.darkgray:hover { background-position-x: -492px; } |
51 |
|
52 |
.no-cssgradients a.yellow, |
53 |
.no-cssgradients a.yellow:visited, |
54 |
.no-cssgradients a.yellow:hover { background-position-x: -574px; } |
55 |
|
56 |
.no-cssgradients a.purple, |
57 |
.no-cssgradients a.purple:visited, |
58 |
.no-cssgradients a.purple:hover { background-position-x: -656px; } |
59 |
|
60 |
.no-cssgradients a.darkblue, |
61 |
.no-cssgradients a.darkblue:visited, |
62 |
.no-cssgradients a.darkblue:hover { background-position-x: -738px; } |
63 |
|
64 |
.no-cssgradients a.button, .no-cssgradients a.button:visited, .no-cssgradients a.button:hover, .no-cssgradients a.button:before, .no-cssgradients a.button:after, |
65 |
.no-borderradius a.button, .no-borderradius a.button:visited, .no-borderradius a.button:hover, .no-borderradius a.button:before, .no-borderradius a.button:after, |
66 |
.no-generatedcontent a.button, .no-generatedcontent a.button:visited, .no-generatedcontent a.button:hover, .no-generatedcontent a.button:before, .no-generatedcontent a.button:after { |
67 |
border: 0; |
68 |
}
|
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!