Make CSS3 buttons that are extremely fancy

Hi everybody! Adam Singer here. Over the coming weeks and months, the rest of the Posterous team and I will be posting to this blog to give you some insight into what powers Posterous. We'll be showing off some cool stuff we've been working on, announce open source projects, and provide some useful tips for those power users out there.

The first installment of the Posterous Technology blog is all about buttons. 

Introduction

Have you ever looked at a button and thought: "This button looks like crap!" This is the kind of thing that keeps me up at night. That's why I made some snazzy buttons that I've dubbed "fancy buttons." Fancy buttons are already in use in our web editor, and we will be adding these buttons throughout the site very soon. Why are these buttons fancy? Well they're fancy for these reasons:

  • Made with pure CSS3. Not a single image was used in the making of these buttons.
  • Scalable. Just change the font size, and the button scales.
  • Colors. Change the background color on the <span> tag and the shine comes with it.
  • Compatible. They look usably satisfactory in IE7 and IE8.

The Code

Before we start, here is what the final product looks like (standard, hover, and click states, respectively):

You can see that these buttons have a nice gloss, as well as some drop shadows for a nice 3D effect. The click state also an inset shadow. To achieve these effects, I needed a small truckload of CSS:

div.fancy_button { 
  float: left;
  border-width: 1px; 
  border-style: solid; 
  border-color: transparent transparent #666 transparent; 
  border-color: transparent transparent rgba(202,202,202,0.27) transparent; 
  -webkit-border-radius: 11px; -moz-border-radius: 11px; border-radius: 11px;
  -webkit-background-clip: padding-box;
}

div.fancy_button a { 
  background: #555; 
  background: -webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,0.4)), to(rgba(77,77,77,0.4)));  
  background: -moz-linear-gradient(top, rgba(0,0,0,0.4), rgba(77,77,77,0.4)); 
  float: left; 
  padding: 4px; 
  text-decoration: none; 
  outline: 0; 
  -webkit-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px;
  -webkit-background-clip: padding-box;
}

div.fancy_button a span { 
  display: block; 
  letter-spacing: -1px; 
  border-width: 1px; 
  border-style: solid; 
  border-color: #ccc #444 #111 #444; 
  border-color: rgba(255,255,255,0.7) rgba(0,0,0,0.3) rgba(0,0,0,0.6) rgba(0,0,0,0.3); 
  font: bold 21px/1em Arial;
  color: white; 
  padding: 0.48em 2em;  
  text-shadow: rgba(0,0,0,0.45) 0 -1px 0; 
  -webkit-box-shadow: rgba(0,0,0,0.75) 0px 0px 3px; -moz-box-shadow: rgba(0,0,0,0.75) 0px 0px 3px; box-shadow: rgba(0,0,0,0.75) 0px 0px 3px;
  -webkit-border-radius: 7px; -moz-border-radius: 7px; border-radius: 7px;
  background: transparent -webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,0.6)), color-stop(0.5, rgba(255,255,255,0.15)), color-stop(0.5, rgba(255,255,255,0.01)), to(transparent)); 
  background: transparent -moz-linear-gradient(top, rgba(255,255,255,0.6), rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.01) 50%, transparent);
  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#80FFFFFF', endColorstr='#00FFFFFF');
  -webkit-background-clip: padding-box; 
}

div.fancy_button a:hover span {  
  border-top-color: rgba(255,255,255,0.65); 
  background: -webkit-gradient(linear, left top, left bottom, from(rgba(220,220,220,0.6)), color-stop(0.5, rgba(100,100,100,0.2)), color-stop(0.5, rgba(0,0,0,0.21)), to(rgba(0, 0, 0, 0.20))); 
  background: -moz-linear-gradient(top, rgba(220,220,220,0.6), rgba(100,100,100,0.2) 50%, rgba(0,0,0,0.21) 50%, rgba(0, 0, 0, 0.20));
  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#99dcdcdc', endColorstr='#33000000'); 
  -webkit-background-clip: padding-box;
}

div.fancy_button a:active span {  
  border-top-color: rgba(255,255,255,0.2); 
  border-left-color: rgba(0,0,0,0.4); 
  background: -webkit-gradient(linear, left top, left bottom, from(rgba(150,150,150,0.6)), color-stop(0.5, rgba(60,60,60,0.6)), color-stop(0.5, rgba(40,40,40,0.6)), to(rgba(20, 20, 20, 0.5))); 
  background: -moz-linear-gradient(top, rgba(150,150,150,0.6), rgba(60,60,60,0.6) 50%, rgba(40,40,40,0.6) 50%, rgba(20, 20, 20, 0.5));
  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#80969696', endColorstr='#59000000'); 
  -webkit-box-shadow: inset 0 0 18px rgba(0,0,0,0.75), rgba(0,0,0,0.75) 0px 0px 3px; -moz-box-shadow: inset 0 0 18px rgba(0,0,0,0.75), rgba(0,0,0,0.75) 0px 0px 3px; box-shadow: inset 0 0 18px rgba(0,0,0,0.75), rgba(0,0,0,0.75) 0px 0px 3px; 
  -webkit-background-clip: padding-box;
}

div.fancy_button a span:active { 
  border-top-color: rgba(255,255,255,0.2); 
  border-left-color: rgba(0,0,0,0.4); 
  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#80969696', endColorstr='#59000000'); 
}

That CSS is definitely quite daunting, but the main reason for the size of the CSS is that many browsers implement different features of CSS, and I wanted to account for as many of them as possible. WebKit-based browsers (Safari and Chrome), Firefox, and Internet Explorer all implement different variants of background gradients and drop shadows. In addition, there were some browser quirks that I had to take care of, such as using -webkit-background-clip to clean up Safari's rendering of rounded corners.

After all this CSS is in place, the HTML is fairly straightforward:

<div class="fancy_button">
  <a href="#">
    <span style="background-color: #070;">Post</span>
  </a>
</div>

I've included the background-color as an inline style for illustration purposes, but you should toss that into your external stylesheet along with the rest of the fancy button code.

Discussion

You may have noticed that I needed a <div>, an <a>, and a <span> to achieve this effect. I'm usually a minimalist when it comes to markup, but I needed to add the extra markup for these reasons:

  • Some browsers don't support multiple backgrounds yet, and some don't support multiple shadows.
  • The fancy buttons are going to be used on Posterous primarily over dark backgrounds. Because of this, I wanted to add a bit of a border around these buttons so that they look "sunk in". This is why the surrounding <div> was necessary. If you don't want the surrounding black "well" around the button, you can get away with just the <a> and <span>.

If you don't care about the dark border around the buttons, you can remove the outer div and simply target the a with a class. 

Changing the font size on the <a>, or the background-color on the <span> will result in buttons of varying sizes and colors. Here are some neat red ones:

Bonus for theme developers: You can use these buttons right now! Simply use the HTML markup above, and the buttons should work—though you may have to override some other styles to get them to look perfect.

Conclusion

So that's it! Our first technology demo has come and gone. If you like what you saw here, or if you have any suggestions for us about making this blog better, we always appreciate your comments!

For those Twitter users out there, we will be autoposting everything from this blog to @posteroustech, so give us a follow!

PS, Posterous is HIRING!