Suppose you want to present an error message to a web user in the form of a stop sign – you know, to get their attention. Let’s further suppose that you don’t know the full text of the message until runtime, so you can’t just use an image. What you want is a stop-sign-shaped section into which you can place text. This is a job for CSS.
The first hurdle on our quest is creating the 45-degree sides of an octagon using web elements that typically prefer orientations in multiples of 90 degrees. But that’s easily accomplished by creating a very wide, beveled border that uses different colors on both sides of the bevel.
Breaking the octagon into five parts like this:
We can see that the left-most portion can be created as a zero-width div section that has a border on three sides that is 1/4th as wide as the entire octagon: the right border being red, while the top and bottom borders are transparent. The same trick can be applied to produce the other three outer edges. The middle area, where we’ll put text, is just square. We then position all four areas using absolute positioning within a container that uses relative positioning.
The final step is to place the text inside an inner div that we can move up or down within the middle section, so we can center it vertically without altering the size of the middle section. Et voila:
Well, at least in Chrome, Firefox, and Safari. When I tried this technique in Internet Explorer 8, I got this masterpiece:
Picasso would be proud. It turns out that the longer dimension for each side needs to be specified twice as big for IE as for all the other browsers. But there is a way to get around it without browser-specific code: specify width or height the way IE wants it, then impose a max-width or max-height that brings it back down for the other browsers.
But I still had a problem with Internet Explorer. For the top and bottom sections, it appeared to ignore height:0px, because each one sported a small, empty rectangle above (the top) or below (the bottom). It turns out that I needed font-size:0px so IE wouldn’t automatically include space for some text (even though it contained none).
But I still had another problem with Internet Explorer. Even after eliminating the space for text, the top side was always placed two pixels too low, resulting in the little rough spots you can see below.
I never figured out why this happens. So I resorted to browser sniffing after all, setting the top of the top section to –2px for IE, 0 for everybody else.
In the download below, you can see a completely static page with no JavaScript in stop_sans_js.html. The IE-specific styling is invoked via a <style> tag that is within an <!—[if IE]> comment tag.
For a more interactive approach, see stop.html and stopsign.js. This invokes a JavaScript function to produce a stop sign of a specified size. The script requires jQuery, which I have also included in the download – and it uses jQuery’s somewhat deprecated $.browser.msie sniffer flag to apply the correct style.
Both versions now work correctly in IE8, Chrome, Firefox, Safari, and Opera. If you use a measurement other than pixels, though, you might run into issues. IE8 especially seems vulnerable to rounding problems, which can leave little gaps between the sections. If the text is too large, the middle box can bump outside its bounds also.
UPDATE 2010-03-24: My original version wasn’t a regular octagon. I was using width / 3 for the length of a side, but it should really be width * (sqrt(2) – 1). I’ve corrected the JavaScript in the download to apply that calculation. I didn’t bother correcting all the hard-coded numbers in the non-JavaScript version.