Realistic CSS3 Buttons Redux

A cou­ple of weeks ago I post­ed Real­is­tic Look­ing CSS3 But­tons, in which I tried to make awe­some-look­ing CSS3 but­tons that required no extra markup. For peo­ple who like more code and less talk, the end of the post has the link to the demo.

As awe­some as they were, they required an explic­it width. This meant that they did­n’t adapt grace­ful­ly to dif­fer­ent labels—you had to explic­it­ly set a width on the but­tons that might not fit the actu­al label prop­er­ly. This had been nec­es­sary to get the nice inner white bor­der, which I’m now using two instances of inset box-shadow to repli­cate (many CSS3 dec­la­ra­tions allow for mul­ti­ples, such as background-image and box-shadow). I would have pre­ferred to do it with only one dec­la­ra­tion, but box-shadow: 0 0 1px #fff inset; pro­duced too dim of an inner bor­der for my liking.

I also want­ed a bet­ter-look­ing but­ton depressed state. I emu­lat­ed the inner shad­ow typ­i­cal of OS X Leop­ard-era but­tons with a third inset box-shadow on the :active state, as you can see below. Press­ing the but­tons feels real­ly awe­some if your brows­er sup­ports CSS Transitions.

States: Nor­mal, Hov­er, Active (left to right)

Speak­ing of CSS tran­si­tions, they’re now used con­sis­tent­ly on the :hover state, by chang­ing the back­ground-col­or on hov­er instead of chang­ing the gra­di­ent (gra­di­ents don’t cur­rent­ly ani­mate in a tran­si­tion). I also did a bit more work to make it cross-brows­er friend­ly: I used back­up col­ors wher­ev­er rgba() nota­tion was used, as well as a gradient.png fall­back for browsers inca­pable of CSS gradients.

Here’s a few things I found along the way:

  • Fire­fox 3.7 night­ly (which will be FF4 even­tu­al­ly I think) ren­ders the but­tons the best.
  • WebKit does­n’t actu­al­ly sup­port inset box-shadow yet in Safari 4 or Mobile Safari. So, they get left behind for now. But WebKit night­ly and Chrome have land­ed sup­port for inset box-shadow.
  • WebKit cur­rent­ly has a fas­ci­nat­ing bug with inset box-shad­ow and tran­si­tions. Using WebKit night­ly or Chrome, try click­ing on the “Wonky Webkit Tran­si­tion” but­ton. The box-shadow starts on the out­side and then snaps to the inside at the end of the transition.
  • Fire­fox does weird things with an :after pseu­do-ele­ment placed on a but­ton ele­ment. I did some hacky things to work around that at the default size using @-moz-document. Not awe­some or recommended.

With­out fur­ther ado (and I use the phrase only to plead with the peo­ple of the world who say “with­out fur­ther adieu” to STOP DOING IT WRONG), check out the Real­is­tic CSS3 But­tons Redux demo.


  1. Posted May 12, 2010 at 2:05 pm | Permalink

    thank you for this Matt.

  2. Posted February 18, 2011 at 12:27 am | Permalink

    Thanks for the tips, now i’m using it on my project 🙂

  3. Kwinto
    Posted April 10, 2011 at 7:50 am | Permalink

    Great work! Thanks 🙂

    back­ground-image: ‑o-linear-gradient(top, rgba(255,255,255,.75), rgba(255,255,255,0));

    to,, {…} class for Opera 11.10+

  4. Matt
    Posted April 10, 2011 at 4:08 pm | Permalink

    @Kwin­to Cheers. As for Opera: yeah, I could do that if I get around to it. I guess some peo­ple use it.