Realistic Looking CSS3 Buttons

UPDATE: I pub­lished Real­is­tic CSS3 But­tons Redux to make even bet­ter buttons.

A while back Mike Run­dle post­ed the ter­rif­ic arti­cle Craft­ing Sub­tle & Real­is­tic User Inter­faces. He clear­ly artic­u­lates design details which make but­tons look real­is­tic and there­fore push-able. If you haven’t read it, go there, spend lots of time look­ing at his excel­lent dia­grams, and then come back. Go even if you for­get to come back.

Then Jay on the Infer­ence blog shared his CSS3 imple­men­ta­tion of Rundle’s but­tons to great effect. He also explic­it­ly shows the design details (with excel­lent dia­grams) that make for press-able but­tons. But, sad­ly, there was very lit­tle “3” in the CSS3, only mak­ing use of bor­der-radius and rgba col­ors. Also, he resort­ed to 3 lay­ers of nest­ed <b> ele­ments inside the <a> ele­ments to imple­ment his effect. I knew that this could be done with lean­er markup, more CSS3 good­ies, zero images, and way more flex­i­bil­i­ty. (Note: this isn’t a cri­tique of Jay’s good work — just an instance where some­one inspires you to try to do bet­ter.)

The end result uses markup that looks like this:

<a href="#" class="button">Pushit</a>

And looks like this:

States: Nor­mal, Hover/Focus, Active (left to right)

Well, it looks that way in Fire­fox (3.6+), Safari & Chrome. I haven’t even test­ed in IE and don’t care to. I’m sure that it’d be pos­si­ble to do this in with prop­er pro­gres­sive enhance­ment, but this was about test­ing the bound­aries 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 weak­ness by far is that I need­ed to set an explic­it width on the but­tons. (Fixed) I could­n’t find a way around this and main­tain my no-extra-markup chal­lenge. Con­sis­tent widths might actu­al­ly be an advan­tage in cer­tain con­texts. (There are some class­es to pro­vide for dif­fer­ent widths.)
  • CSS3 gra­di­ents galore. Not an image in sight.
  • The extra bor­ders are cre­at­ed using :after and :before pseudo-elements.
  • The CSS3 gra­di­ents use rgba col­or nota­tion with alpha val­ues so that you can have dif­fer­ent coloured but­tons by chang­ing only the back­ground-col­or. (I assigned a few colour exam­ples to extra classes)
  • Real <input type="submit" /> but­tons don’t allow :after and :before pseu­do-ele­ments. Form ele­ments are weird.
  • CSS gra­di­ents are cur­rent­ly avoid­ed by ‑webkit/-moz-tran­si­tion. Brief googling indi­cat­ed per­for­mance con­cerns. If you want­ed the ooh shiny™, you could change the background-color on the :hover/:active states instead. I avoid­ed this because I only want­ed to have to declare a sin­gle background-color for col­or class­es, but tried it in the obvi­ous­ly-labeled button.

Tired of read­ing? Look at some real­is­tic look­ing CSS3(-only) but­tons. And if any­one has any ideas about how to over­come the fixed-width require­ment, do share!


  1. Posted April 19, 2010 at 3:25 pm | Permalink

    Excel­lent, I real­ly like how you imple­ment­ed the emboss effect using :after and :before. Nev­er seen that tech­nique used to cre­ate bor­ders before, very nice!

  2. Matt
    Posted April 20, 2010 at 10:32 am | Permalink

    Thanks Bryan. The :before and :after pseu­do-ele­ments are sad­ly under­used due to no sup­port in IE6 & 7. 

    In this case the but­tons would still work fine, they just would­n’t have the nice extra borders.

  3. Posted April 22, 2010 at 10:57 am | Permalink

    I saw your post on Dribb­ble, but since I don’t have an account I could­n’t com­ment there.. but for­tu­nate­ly I can here!

    First off, you might con­sid­er tak­ing a look at some CSS3 but­tons I made a few days ago:

    A cou­ple of things you might consider:

    Drop :before and :after alto­geth­er and just use inset box shad­ows. For this you can use ‑webkit-box-shad­ow, ‑moz-box-shad­ow, and box-shadow.

    Check out <but­ton /> instead of <input type=“submit” />, as :before and :after work there. The rea­son they don’t work on s is because they don’t real­ly have con­tent, just the value.

    Let me know if that helps you solve the prob­lems you were having!

  4. Matt
    Posted April 22, 2010 at 4:36 pm | Permalink

    @Bran­don Good work on those but­tons! As for using inset box shad­ows, there were two rea­sons not to: 1) last I’d heard that inset was­n’t sup­port­ed in webkit, but that appears to have changed. 2) inset box-shad­ow does­n’t give that nice sol­id 1px edge all the way around that I wanted.

    You’re right that <but­ton> sup­ports :after and :before (good catch), but it still comes out bad­ly due to the inher­ent issues with styling form ele­ments. (See link in post).

    BUT, inset box-shad­ow would make for a much nicer depressed state I think. I might have to try a new revi­sion with those.

    (PS fixed your miss­ing html and delet­ed your com­ment about it.)

  5. Posted April 22, 2010 at 11:29 pm | Permalink

    There is still a bug ( that pre­vents the inset box shad­ows from being drawn cor­rect­ly in Webkit, but that real­ly only affects the but­tons with a large bor­der-radius (the larg­er the radius, the more of the back­ground shows through).

    As for get­ting a sharp bor­der all the way around, con­sid­er some­thing like ‑webkit-box-shad­ow: white 0px 0px 2px inset;

    There’s still a lot of room for improve­ment on CSS3, but I’m look­ing for­ward to the fea­tures we’ll see in the com­ing months!

  6. Lola LB
    Posted May 5, 2010 at 12:13 pm | Permalink

    Your link to ” real­is­tic look­ing CSS3(-only) but­tons” leads to a dead end. Is it up, or is the URL mal-formed? Thanks!

  7. Matt
    Posted May 5, 2010 at 12:28 pm | Permalink

    @Lola Thanks, the link works again. I moved some things around over the week­end and this was forgotten.

  8. Posted July 10, 2010 at 12:55 am | Permalink

    I had pre­vi­ous­ly cre­at­ed the Cad­mus post but­ton in Pho­to­shop and it was essen­tial­ly three images for the dif­fer­ent states. I want­ed to use this style for all.

  9. Posted September 21, 2010 at 7:59 am | Permalink

    i like your way of teach­ing it forces guys to actu­al­ly read and fol­low whats going on, as opposed to copy past­ing — lol.

  10. Corello
    Posted January 27, 2012 at 3:25 pm | Permalink

    Quite nice but­tons and tutorial.

    Although, you prob­a­bly should have added a space (after the “h” and def­i­nite­ly not before the “s”) in the but­ton text… !!

  11. Posted April 2, 2012 at 8:23 am | Permalink

    Hey, I faced the same fixed width prob­lem a lot of times. I just want­ed to let you know that I have suc­cess­ful­ly used jQuery in some cas­es and got around this problem! 🙂

  12. Posted December 21, 2012 at 6:37 am | Permalink

    I am cus­tomiz­ing some “read more” but­tons and this post pro­vid­ed some great insight.

    Many thanks,

4 Trackbacks

  1. By CSS3 buttons » Common Agency on May 12, 2010 at 3:39 am
  2. By April’s Best Resources for CSS3 on May 26, 2010 at 5:24 pm