UPDATE: I published Realistic CSS3 Buttons Redux to make even better buttons.
A while back Mike Rundle posted the terrific article Crafting Subtle & Realistic User Interfaces. He clearly articulates design details which make buttons look realistic and therefore push-able. If you haven’t read it, go there, spend lots of time looking at his excellent diagrams, and then come back. Go even if you forget to come back.
Then Jay on the Inference blog shared his CSS3 implementation of Rundle’s buttons to great effect. He also explicitly shows the design details (with excellent diagrams) that make for press-able buttons. But, sadly, there was very little “3” in the CSS3, only making use of border-radius and rgba colors. Also, he resorted to 3 layers of nested <b> elements inside the <a> elements to implement his effect. I knew that this could be done with leaner markup, more CSS3 goodies, zero images, and way more flexibility. (Note: this isn’t a critique of Jay’s good work — just an instance where someone inspires you to try to do better.)
The end result uses markup that looks like this:
<a href="#" class="button">Pushit</a>
And looks like this:

States: Normal, Hover/Focus, Active (left to right)
Well, it looks that way in Firefox (3.6+), Safari & Chrome. I haven’t even tested in IE and don’t care to. I’m sure that it’d be possible to do this in with proper progressive enhancement, but this was about testing the boundaries of CSS3.
I’m not going to break down the code here. That’s what Firebug/Inspector/View Source are for. But here are some notes:
- The biggest weakness by far is that I needed to set an explicit width on the buttons. (Fixed) I couldn’t find a way around this and maintain my no-extra-markup challenge. Consistent widths might actually be an advantage in certain contexts. (There are some classes to provide for different widths.)
- CSS3 gradients galore. Not an image in sight.
- The extra borders are created using
:after
and:before
pseudo-elements. - The CSS3 gradients use rgba color notation with alpha values so that you can have different coloured buttons by changing only the background-color. (I assigned a few colour examples to extra classes)
- Real
<input type="submit" />
buttons don’t allow:after
and:before
pseudo-elements. Form elements are weird. - CSS gradients are currently avoided by ‑webkit/-moz-transition. Brief googling indicated performance concerns. If you wanted the ooh shiny™, you could change the
background-color
on the:hover
/:active
states instead. I avoided this because I only wanted to have to declare a singlebackground-color
for color classes, but tried it in the obviously-labeled button.
Tired of reading? Look at some realistic looking CSS3(-only) buttons. And if anyone has any ideas about how to overcome the fixed-width requirement, do share!