Posted by Kevin D Smith @ 11:21 pm on December 2nd 2008

Simple Variable-Width Buttons with Backgrounds in CSS

A lot of times when people create buttons on web pages, they want them to have nice gradients in the background and rounded corners and such. The trouble is that in order to create nice looking buttons like that, you either have to make the button contain the text itself, or you have to chop up the image into pieces and use the sliding door technique. The problem with putting the text in the image is that it is much more difficult to do translations. The sliding doors technique is annoying because you have to chop your images up. However, there is a third way which is much easier and will work in most cases.

The third technique is a lot like the sliding doors technique, but doesn’t require you to chop the image up. All that it requires is an image that looks like the button you want to create and is wider than any content that you may want to put into it. We’ll use the button shown below.

We are going to create a typical dialog style button bar with an OK button and a Cancel button. The HTML for this is shown below.

<div id="dialog">
<a href="/"><span>OK</span></a>
<a href="/"><span>Cancel</span></a>
</div>

Each button in this code consists of both an <a> tag and a <span> tag. The names of the tag aren’t important, but you do need to have two of them: one to render the left side of the button and the other to render the right side of the button. In our example, we are going to use the <span> tag to render the left side and the <a> tag to render the right side. Let’s start with the left side first.

The CSS code below will put our button image behind the <span> tag as well as set the height of the element to the same height as the background image and set the appropriate font size.

#dialog a span {
    background: transparent url('button.png') no-repeat scroll left 0;
    display: -moz-inline-box;
    display: inline-block;
    height: 22px;            /* Same as height of background image */
    font: 16px/22px "Lucida Grande", Arial;
}

We used the inline-block display type so that we could set the height of the button properly. Since Firefox 2 doesn’t support the inline-block type, we had to use -moz-inline-box as well. With these rules applied to our HTML, we get the following representation.

The text is crammed onto the left side, so add the following padding rule to the above CSS code to give us some room on the left side.

padding: 0 0 0 15px;

Our buttons should now look like the following.

We’re almost there, we just need to get the right hand side of the buttons rendered. Of course, that’s where the trick comes in. We are going to add 15px of margin to the right of each <span> tag (using margin: 0 15px 0 0). This will allow 15px of the <a> element to show through. We then use the same background image that we used for the <span> element except that we align it to the right side of the element. Here is the CSS rule for the <a> tag.

#dialog a {
    background: transparent url('button.png') no-repeat scroll right 0;
    display: -moz-inline-box;
    display: inline-block;
    height: 22px;
    font: 16px/22px "Lucida Grande", Arial;
}

We now have nice looking buttons using just a single image and CSS!

Since most of the rules for the <span> and <a> tag are the same, we can combine those rules and just override the differences in a second rule. We’ll also add a couple of attributes to set the color of the text and turn off any link underlining.

#dialog a, #dialog a span {
    background: transparent url('button.png') no-repeat scroll left 0;
    margin: 0 15px 0 0;       /* 15px == amount of background image to the right */
    padding: 0 0 0 15px;      /* 15px == amount of background image to the left */
    display: -moz-inline-box; /* Firefox 2 support for inline-block */
    display: inline-block;    /* Must be used so that height can be set */
    height: 22px;             /* Same as height of background image */
    font: 16px/22px "Lucida Grande", Arial; /* Appropriate font size / line height */
    color: black;
    text-decoration: none;
}
#dialog a {
    background-position: right 0;
    margin: 0;
    padding: 0;
}

Here is the final result.

Not only can you use this technique for buttons, but you can also use it to style tabs the same way. While this isn’t a perfect solution since it requires a fixed height font to be used in the button, it is a simpler way of handling styled buttons since you don’t have to worry about slicing and dicing your button backgrounds.