PDA

View Full Version : Creating bulletproof graphic link buttons with CSS


456 Berea Street
23rd May 2007, 06:24 am
A CSS problem I have been wrestling with lately is how to create a bulletproof shrinkwrapping graphic button. By that I mean an image-based button that will expand and contract to fit the amount of text it contains. It is a very useful technique for CMS-driven sites that allow the client to change the text that is displayed on buttons, as well as for multilingual sites.
A successfull bulletproof image-based button should:

Automatically grow horizontally to fit any amount of text
Grow horizontally and vertically if text size is increased or if the text wraps to multiple lines
Retain its appearance within reasonable limits
Be able to have rounded (or other non-square) corners
Have no unclickable areas
Be readable when images are disabledDoing this with CSS may sound easy at first, but there are several things to be considered that make it a little tricky. I also ran into several browser related problems before ending up with the solution described in this article.
The problems, as always when it comes to CSS, occur in Internet Explorer. The first problem is one that I'm not actually sure whether it is a bug or just a different implementation of the specification. I mentioned the problem in Transparent custom corners and borders, version 2 (http://www.456bereastreet.com/archive/200609/transparent_custom_corners_and_borders_version_2/), and it consists of IE having problems figuring out the width of block level elements inside floated elements with no width assigned.
When a floated element has no specified width, the browser should adjust the element's width to fit its content – shrinkwrapping. In the case of a floated link acting as a button, that would come in handy as it will make the link automatically adjust its width depending on the amount of text it contains. Sadly, Internet Explorer will not properly shrinkwrap the following combination of HTML and CSS I use for the Transparent custom corners and borders technique.





A box (http://www.websitearchitecture.co.uk/forum/#)






When div.cb is floated without a specified width, it will shrinkwrap to fit its content. The width depends on the content of div.i1, and that part works fine. The problem is with the div.bt and div.bb elements, which don't expand to the same width as div.i1. That kind of makes sense, since they are empty siblings of div.i1. A workaround is to give div.cb a width, but I really needed shrinkwrapping buttons, so I had to to come up with something else.
I ran into the second problem while exploring other solutions and experimenting with absolutely positioning the corners. That actually worked, except for a one pixel gap that showed in IE at certain sizes, probably due to a rounding error.
What I ended up with is a link that contains four nested span elements. Here's the markup for a button (nicely indented here for readability):





Shrinkwrap me!



(http://www.websitearchitecture.co.uk/forum/#)Yes, I know. That is a lot of span elements. It isn't pretty, but I can't think of a better way to achieve this effect until more browsers than Safari support Layering multiple background images (http://www.w3.org/TR/css3-background/#layering). In a production situation I would use a script similar to the one in Transparent custom corners and borders, version 2 (http://www.456bereastreet.com/archive/200609/transparent_custom_corners_and_borders_version_2/) to remove the span elements from the markup. The end result is the same to the browser, but the markup is cleaner for us humans who have to edit it.
And of course we need a bit of CSS to turn that markup into a nice-looking button:

.button { /* Top left corner, top edge */
float:left;
color:#ddd; /* Text colour */
background:#333 url(button.gif) no-repeat; /* Fallback bg colour for images off */
font:1.2em/1.0 Georgia,serif;
text-decoration:none;
}
.button * {display:block;}
.button .tr { /* Top right corner */
padding:6px 0 0;
background:url(corners.gif) no-repeat right top;
}
.button .bl { /* Bottom left corner, left and bottom edges */
padding:0 0 0 6px;
background:url(button.gif) no-repeat left bottom;
}
.button .br { /* Bottom right corner */
padding:0 0 6px;
background:url(corners.gif) no-repeat right bottom;
}
.button .r { /* Right edge */
padding:3px 12px 3px 6px; /* Extra padding (3px vertical, 6px horizontal) added to give the text some breathing room */
background:url(button.gif) no-repeat right center;
}
.button:hover,
.button:focus,
.button:active { /* Help keyboard users */
outline:2px solid #ff0; /* Not supported by IE/Win :-( */
color:#fff;
}You'll need to adjust the paddings to fit your image if it has wider or narrower corners and edges.
Oh, I made a demo page (http://www.456bereastreet.com/lab/bulletproof-shrinkwrapping-buttons/) that contains a few buttons.
Ideally, this kind of button would be accomplished by using a single background image, so that was my initial goal. I did not manage to reach that goal, however, but had to resort to using two images. The two images are button.gif (http://www.456bereastreet.com/lab/bulletproof-shrinkwrapping-buttons/button.gif) and corners.gif (http://www.456bereastreet.com/lab/bulletproof-shrinkwrapping-buttons/corners.gif). If you take a look at them, you will notice that they are much larger than any button should become since they define the maximum size of the button. If you need even larger buttons, just increase the size of the images.
Note that corners.gif (http://www.456bereastreet.com/lab/bulletproof-shrinkwrapping-buttons/corners.gif) is transparent except for in the corners. That way it can be used to put each corner in place without covering any of the other corners.
And that's it. A bulletproof, resizable, shrinkwrapping graphic button.
There are a few caveats though:

The corners can't be transparent
It may be tricky to give the button a non-flat background colour
It only expands as far as the size of your imageTo me, those are completely acceptable drawbacks in most situations.
So, does anyone see how this could be further improved?
Visit site to read or post comments… (http://www.456bereastreet.com/archive/200705/creating_bulletproof_graphic_link_buttons_with_css/#comments)Add 456 Berea Street to your Technorati favorites. (http://technorati.com/faves?add=http://www.456bereastreet.com)
Posted in CSS (http://www.456bereastreet.com/archive/categories/css/).
http://feeds.feedburner.com/~a/456bereastreet?i=JgZ1PW</img> (http://feeds.feedburner.com/~a/456bereastreet?a=JgZ1PW)
http://feeds.feedburner.com/~f/456bereastreet?i=DfCkylrm</img> (http://feeds.feedburner.com/~f/456bereastreet?a=DfCkylrm) http://feeds.feedburner.com/~f/456bereastreet?i=hIxUd4MG</img> (http://feeds.feedburner.com/~f/456bereastreet?a=hIxUd4MG) http://feeds.feedburner.com/~f/456bereastreet?i=1bLOVWqH</img> (http://feeds.feedburner.com/~f/456bereastreet?a=1bLOVWqH)


More... (http://www.456bereastreet.com/archive/200705/creating_bulletproof_graphic_link_buttons_with_css/)