Styling the button element with sliding doors
Posted by Scott and Maggie on 05/23/2007
- Topics:
- css
- ui design
- visual design
Particle Tree recently posted an article describing a technique for styling the HTML button element. For those not familiar, form buttons are notoriously difficult to customize because they render differently across browsers and platforms. The typical solutions are to use the default button style that the browser provides, or use an image input, which may look fine but requires that you create a unique background image with text "baked in" for each type of button (i.e., "Enter", "Send message") and its rollover state.
While Particle Tree's technique works well, we needed a more flexible solution that accommodated a wider range of styles. We're often designing and developing complex applications with buttons that are styled with background images, background colors, icons, and sometimes a combination of all three. Ideally, our buttons would:
- use the sliding doors method introduced on A List Apart,
- allow us to use HTML text for the button labels so that we could reuse the same button style many times without having to cut unique images for each, and
- do not require JavaScript for form submission or rollovers.
To meet these conditions we developed the following technique — a cross-browser method for styling button elements with sliding doors.
Examples
Each button shown uses the same markup and style — only the label text is different.
Images & Markup
We cut two images for each state, default and hover (4 images total). The first pair form the left side of the button, the second form the right side.
Left corners:


Right corners:


(We'd like to convert these states into two sprites, where the default and hover state for each are burned into a single background image that is repositioned on hover. Initial testing for that idea yielded inconsistent results — if you have any success with this, please drop us a line.)
Button markup consists of a button tag around a span tag, and label text is written into the span. Both tags are necesary to support the two sliding door background images: the button tag's background image is shorter with right corners, and the span's background image is the larger with left corners. We found in our tests that it's best to cut the right image at least as wide as it is tall to avoid gaps between the doors.
And last but not least, the "submitBtn" class is assigned to the button tag (styles for the span tag are assigned with descendant selectors):
<button value="submit" class="submitBtn"><span>Submit</span></button>
CSS
button {
border:0;
cursor:pointer;
font-weight:bold;
padding:0 20px 0 0;
text-align:center;
}
button span {
position:relative;
display:block;
white-space:nowrap;
padding:0 0 0 20px;
}
/*blue buttons*/
button.submitBtn {
background:url(images/btn_blue_right.gif) right no-repeat;
font-size:1.3em;
}
button.submitBtn span {
height:50px;
line-height:50px;
background:url(images/btn_blue_left.gif) left no-repeat;
color:#fff;
}
button.submitBtn:hover {
background:url(images/btn_blue_right_hover.gif) right no-repeat;
}
button.submitBtn:hover span {
background:url(images/btn_blue_left_hover.gif) left no-repeat;
}
CSS for IE 6 and 7
We recommend referencing these in a dedicated IE stylesheet using conditional comments.
button {
width:auto;
overflow:visible;
}
button span {
margin-top:1px;
}
Supported Browsers
So far we've tested: IE 6, IE7, Firefox (Mac + PC), Safari, Opera, Camino
Caveats
IE 6 does not support the ":hover" pseudoclass on elements other than anchor tags. To get the hover to work in IE6, you'll need to duplicate the :hover styles and assign them a class name, and then script a function to toggle that class on/off.
Credits
This technique was motivated by the Particle Tree article Rediscovering The Button Element. The "width: auto;" workaround for IE is a technique we discovered at Jehia.cz.
Comments
thank you
Comment by komik on 03/10 at 01:41 PM
First off, very nice post.
Second, I think your ATOM feed is serving the wrong URL in the feed item url. For example this post’s url is served as http://www.filamentgroup.com/<strong>site</strong>/styling_the_button_element_with_sliding_doors/
instead of http://www.filamentgroup.com/<strong>lab</strong>/styling_the_button_element_with_sliding_doors/
It should only affect people trying to follow the link out of their feed reader, or folks like me who use the Google Reader Bookmarklet.
Comment by Mike Busch on 03/14 at 12:58 PM
@Mike: Thanks! It should be fine now.
Comment by Scott (Filament) on 03/16 at 05:01 PM
TIPS : adding css :
button:focus::-moz-focus-inner { border-color: transparent ! important; }
put away that dotted outline showed in firefox…
Comment by Nebz on 03/28 at 05:26 PM
I’d advice against the previously posted -moz-focus-inner tip. The dotted outline is an important clue when navigating without the mouse.
Comment by Thomas Thomassen on 03/31 at 10:00 AM
Very good thanks
Comment by dekorasyon on 04/03 at 08:35 AM
Thanks for this great post.
Though, one thing that’s kinda odd is the “not so similar” behaviour in Mozilla and Safari 3.1.
If I add a 10px padding to make the button look nice in Moz it somehow “breaks” Safari - resulting in odd paddings (ie left padding being bigger than right, although both are 10px). Anyone got an idea on how to solve this?
For now I will make the button look “good” in Mozilla because of its market share
But still, great approach. Thanks a ton!
Comment by sebastian on 04/11 at 04:44 AM
@Thomas Thomassen
True… but it don’t display well… only one part of the button is dotted… i would advice to add the pseudo-class :focus in css to have the clue without the semi-dotted button (tested in firefox only)
button.submitBtn:hover,button.submitBtn:focus {
background:url(images/btn_blue_right_hover.gif) right no-repeat;
}
button.submitBtn:hover span, button.submitBtn:focus span {
background:url(images/btn_blue_left_hover.gif) left no-repeat;
}
Comment by Nebz on 04/11 at 09:31 AM
@Sebastian—sometimes adding padding requires a bit of fine-tuning in order to work correctly across browsers. The example buttons on this page look the same in Firefox and Safari, so If you post your markup/CSS or a link to an example page we may be able to help you debug. (If you post markup as a comment, remember to encode your characters.)
Comment by Maggie (Filament) on 04/11 at 09:42 AM
How would one do this with an input type button?
Like this…
input type="button" value="SEARCH"
Comment by Veronika on 04/11 at 06:44 PM
This can’t be done with input type buttons… because you can’t set HTML in the value (this hack need a span in the value)
in <body> :
<form id=’myForm’ action=’blah.cgi’ method=’post’>...<button id=’submitButton’ class=’submitBtn’><span>Submit</span></button></form>
in <head> :
document.onload=function(){
document.getElementById(’submitButton’).onclick=function(){document.getElementById(’myForm’).submit()}
}
or with prototype framework (recommended):
document.observe("dom:loaded", function() {
$(’submitButton’).observe(’click’,function(){$(’myForm’).submit()});
});
Comment by Nebz on 04/12 at 03:54 PM
I used to skin the button as detailed in http://www.wakeim.com/view/dynamic-custom-form-buttons-with-css/. Here the right piece would not allow the click and moreover, the display:block / float:left put the button in a new line which could be painful in many a cases.
This workaround is superb.
Comment by Sridhar on 04/18 at 05:38 AM
Why to use 4 images if enought two without ‘span’?
For example:
button {
...
background: url(images/btn.gif);
}
button:hover{
...
background: url(images/btn_hover.gif);
}
Comment by phone cards on 05/14 at 06:38 AM