Pure CSS Buttons

Designing the perfect button on the web is impossible. Designing an almost perfect button is a choose-your-own-adventure of compromises. Want rounded corners in all browsers? Use lots of markup, images, and/or javascript. Want the width and height to stretch to fit the content? Welcome to float hell. Want a textured background? Hope you can get by with a single background image.

After years of adapting my buttons to meet my needs, the compromise I've chosen is to have the button keep its default inline display policy (only stretch lengthwise) and to have CSS3 rounded corners (no rounded corners for IE6/7/8). This implementation requires zero extra markup and zero javascript, and as such it's rendered fast in modern browsers and degrades gracefully in others. Also, I think they're kinda pretty :)

The buttons

Here are the buttons in action:

These are just <button> elements with the designated class names. No extra HTML.

The CSS

Let's dive into the CSS. First we'll declare the rule for a plain old button. We'll start out with a bold font, some coloring, borders, a background image, and padding:

  • button {
  • font-weight: bold;
  • background: #e4e5e9 url(button-bg.png) repeat-x left top;
  • border: 1px solid #bec3cd;
  • border-bottom-color: #88909f;
  • padding: 0.15em 0.55em;
  • color: #394148;
  • }

The background image is 1px wide and repeated horizontally to create a gradient effect. It has been aligned to the top, so the background color should match the color of the bottom-most pixel in the background image so that it fades seamlessly when the button is stretched vertically.

Now let's add the rounded corners:

  • button {
  • font-weight: bold;
  • background: #e4e5e9 url(button-bg.png) repeat-x left top;
  • border: 1px solid #bec3cd;
  • border-bottom-color: #88909f;
  • padding: 0.15em 0.55em;
  • color: #394148;
  • -moz-border-radius: 100%;
  • -webkit-border-radius: 1em;
  • border-radius: 100%;
  • }

Now let's add some interactive styles. My way of affording button interactivity is to lighten up the background, darken the borders, and change the cursor. I like both the :focus and :hover states to have the same style, because they both mean "You can interact with this element."

  • button:focus,
  • button:hover {
  • color: #27292b;
  • border-color: #a0a6b3 #a0a6b3 #5d6574;
  • background-image: url(button-bg-hover.png);
  • cursor: pointer;
  • }

"What about :active?", you say? Aren't you astute! In terms of buttons, "active" refers to when the button is "pressed" or, more programmatically, "down". To make the button appear pressed we simply invert the background gradient:

  • button:focus,
  • button:hover,
  • button:active {
  • color: #27292b;
  • border-color: #a0a6b3 #a0a6b3 #5d6574;
  • background-image: url(button-bg-hover.png);
  • cursor: pointer;
  • }
  • button:active {
  • background-color: #fff;
  • background-image: url(button-bg-down.png);
  • }

That's it for a clickable button, but what about when it's disabled? A disabled button should not afford interactivity, so we should make it flat and translucent so it fades into the background, as well as revert the cursor to its default icon. We should also be sure to override all interactive states:

  • button.disabled,
  • button.disabled:focus,
  • button.disabled:hover,
  • button.disabled:active {
  • border-color: #bec3cd;
  • color: #394148;
  • background-color: #e4e5e9;
  • background-image: url(button-bg.png);
  • cursor: default;
  • opacity: 0.5;
  • -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; /* IE 8 */
  • filter: alpha(opacity=50); /* IE 6/7 */
  • }

The three opacity rules are necessary to get our translucent effect working in our targeted browsers. See this Quirksmode article for more details on cross-browser opacity.

Putting it together

Finally, here are all of our default button rules in one package:

  • button {
  • font-weight: bold;
  • color: #394148;
  • background: #e4e5e9 url(button-bg.png) repeat-x left top;
  • border: 1px solid #bec3cd;
  • border-bottom-color: #88909f;
  • padding: 0.15em 0.55em;
  • -moz-border-radius: 100%;
  • -webkit-border-radius: 1em;
  • border-radius: 100%;
  • }
  • button:focus,
  • button:hover,
  • button:active {
  • color: #27292b;
  • border-color: #a0a6b3 #a0a6b3 #5d6574;
  • background-image: url(button-bg-hover.png);
  • cursor: pointer;
  • }
  • button:active {
  • background-color: #fff;
  • background-image: url(button-bg-down.png);
  • }
  • button.disabled,
  • button.disabled:focus,
  • button.disabled:hover,
  • button.disabled:active {
  • border-color: #bec3cd;
  • color: #394148;
  • background-color: #e4e5e9;
  • background-image: url(button-bg.png);
  • cursor: default;
  • opacity: 0.5;
  • -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; /* IE 8 */
  • filter: alpha(opacity=50); /* IE 6/7 */
  • }

To change the look and feel of our button, simply override all color, background-color, border-color, and background-image properties like so:

  • button.blue {
  • background: #9fc1df url(button-blue-bg.png) repeat-x left top;
  • border-color: #99b9db #99b9db #4978ad;
  • color: #20324e;
  • }
  • button.blue:focus,
  • button.blue:hover,
  • button.blue:active {
  • color: #27292b;
  • border-color: #7fa5d0 #7fa5d0 #224e7f;
  • background-color: #add1f1;
  • background-image: url(button-blue-bg-hover.png);
  • }
  • button.blue:active {
  • background-color: #fff;
  • background-image: url(button-blue-bg-down.png);
  • }
  • button.blue.disabled,
  • button.blue.disabled:focus,
  • button.blue.disabled:hover,
  • button.blue.disabled:active {
  • border-color: #99b9db;
  • color: #20324e;
  • background-color: #9fc1df;
  • background-image: url(button-blue-bg.png);
  • }