Web Matters

CSS buttons


Note: this article was originally written when Internet Explorer 5 was still widely used and Netscape 4 was not exactly rare. Times have moved on, and IE 5 usage has now dropped to the point where it is surely safe to ignore it completely, as is the case with Opera versions before 9.

Generally I would encourage web-designers to support even little-used older browsers – providing reduced functionality – if it is a question of coping with a missing feature. When however the feature was implemented, but with serious bugs, there comes a point when it is no longer worth the effort.

Producing a functioning CSS button-bar is therefore quite a bit simpler than it used to be, and on another page I cover a more modern approach.


This page explains how one can put button-bars (menus) together using CSS – no images are required. Compared to using images this has various advantages.

In principle this is fairly simple to do, but various browser bugs introduce subtle points which need to be paid attention to. This page assumes the reader has some basic knowledge of CSS.

Note that this page is mainly concerned with horizontal button-bars. Vertical button-bars are much more straightforward.

Examples

Here are examples of the button-bars which are possible. Don’t worry if the colour scheme makes you cringe – you can easily change it to whatever you like. (In older browsers these will just appear as a list of links.)

Example contiguous button-bar:

Example spaced button-bar:

In principle if you know just a little CSS you should simply be able to pick up these examples from the page source and use them. However if you wish to change some aspects you will need to know why certain things are done as they are. The rest of this page explains this.

Basics

The basics are straightforward: you declare the links as an unordered list with an ID of, say, “navbar” <UL ID="navbar"> and set the CSS property #navbar LI {display: inline} to get the links to appear in a row. Of course you can use a class instead of an ID if you think you might want more than one button-bar per page with the same styling.

To get the button-bar centered on the page you need to add the following properties: #navbar {text-align: center; margin-left: 0; padding-left: 0;}. The first is self-explanatory; the others are to remove the extra margin that browsers normally put in to display the bullets in a bulleted list (some browsers use margin and some use padding). You can of course set margin or padding on all four sides if you wish.

Then you apply #navbar A {text-decoration: none} to remove the underlines from the links. Generally this is not a good idea, as it leaves the reader to guess what text might be links. It is certainly abused on many web-sites (the result is often referred to as “mystery-meat” navigation). But in this context, when the links are part of a clearly identifiable button-bar, this is not a problem.

Finally you apply to the <LI> elements whatever colours, border, padding and margin you want, to achieve the required look. You can of course look at the source code of this page for an example.

Cross-browser aspects

Wrinkles

But now we come to the first browser wrinkle: Netscape 4 and one or two other older browsers support CSS very badly, especially the padding/border/margin properties. The number of users of these browsers is now so small that it makes little sense to worry very much about cosmetics for them, but not yet so small that it makes sense to ignore them completely. For these browsers it is best to hide the CSS by placing it in a separate file, which is included by an ‘@import’ rule – something which these browsers ignore. They then display a standard bulleted list of links – not beautiful, but perfectly functional. On this page the styles for the button-bars are in the file ‘navbar.css’.

Two other wrinkles:

  1. If one wants to change the foreground colour for link / visited / hover states, but leave the button background the same, it might seem sensible to define the background once on the A element, e.g. #navbar A {background-color: #FF8000} and then define only the foreground colour on the anchor pseudo-classes: #navbar A:link {color: black} etc. However this falls foul of a bug in the Konqueror browser, so it is best to define both background and foreground colours on all the anchor pseudo-classes.
  2. On the other hand if you want a different font-size, such as 90% or 110%, then you should define this in #navbar A and not in the pseudo-classes, as some browsers ignore font-size changes in pseudo-classes (this is permitted by the CSS specification).

The IE 5.0 kludge

I described the above aspects as wrinkles - they are things you need to be aware of, but there is a perfectly good solution. However we now come to something which can only be described as a kludge, because the technical solution is ugly. The end result to the user is pretty acceptable though.

IE 5.0 fails to display borders and padding on inline elements. This means the buttons get scrunched up together. This might just be acceptable if every button text consists of a single word. For multi-word buttons however, the result is a mess:

[Nav-bar with words closely spaced].
(screen-shot: Nikolaos Giannopoulos)

This can be addressed by inserting extra spaces and (optionally) a vertical bar character in a way that only IE 5.0 sees. This can be done by turning one of the IE 5.0 bugs on itself, as described on the site Hiding CSS from buggy browsers. The extra characters between each pair of links are placed in a span: <SPAN CLASS="ie5sep">&nbsp;&nbsp;|&nbsp;&nbsp;</SPAN>

The CSS class is defined as follows: .ie5sep/* */ { display: none; } IE 5.0 gets confused by the comment immediately after the class name. It misses the "display: none" and so displays the spans with the 'ie5sep' class.

This results in something like the following:

[Nav-bar with words properly spaced].
(screen-shot: Julián Hidalgo)

When it comes to IE bugs however, it is just about impossible to cope with everything. Matt Broughton pointed out to me that IE 5.2 for the Mac has the comment bug, so displays the extra vertical bars, but also displays the borders. Just for good measure it also displays too much padding!

Wrapping

The above works nicely as long as the reader’s window is wide enough to accomodate the whole button-bar on one line. If however he has a small window, or a large font selected, the buttons need to float gracefully to the next line. (This is something which all too many web designers forget completely.)

If you’ve followed the instructions above, the buttons probably already wrap. But to ensure they look good you need to address the following points:

Keeping a button together

This ought to be straightforward: #navbar A {white-space:nowrap} Unfortunately this hits a bug in both Opera 6 and 7, which do support this property, but seem to get it wrong when applied to consecutive inline elements – wrapping is suppressed for the whole button-bar instead of the individual buttons.

Therefore a safer, if less elegant, solution for the moment is to use non-breaking spaces – &nbsp; – to link multiple words on a button.

Hyphens form another challenge. The non-breaking hyphen is not supported by all browsers: some display “&#8209;” or a block character, which isn’t very reader-friendly. If you really can’t just omit the hyphen, the best solution for the moment is probably to use the no-break element – <NOBR> – which is not included in the HTML specification but nonetheless seems to be supported by most, if not all, current browsers. The same applies if you feel the need to use characters like ‘/’, which allow line-breaks in some browsers but not others.

White space

There must somewhere be some white space between the button texts, so that the buttons can float to the next line. If you put the <LI> elements each on a new line, as one normally does, then that gives you white space. Problem solved, you might think, but there is a little more to it than that.

If you have no white space within the <LI> elements, the line-break between the <LI> elements is indeed treated as white space, at least by conforming browsers such as Opera and Mozilla. This gives spaces between buttons. (IE 6 seems to recognise this as being somewhere it can break the line, but for some reason doesn’t display the spaces.)

To get the contiguous button-bar one introduces (paradoxically, it may seem) extra white space somewhere else. If one has a space within the <LI> element, somewhere after the button text, then this space comes first and is recognised as white space, so the line-break between the <LI> elements counts as duplicate white space, and is suppressed. So the buttons join together.

Thus one needs at least one space character either before or after the </A> tag. It wouldn’t matter which, if it wasn’t for browser bugs.

Grey hair

I will first describe the bug situation without the IE 5 kludge, as I can imagine some people will prefer not to use it.

If the space comes after the </A> tag, Opera 6 incorrectly places a space between the buttons. If the space comes before that tag, IE 6 incorrectly “bleeds” the background colour rather unpleasantly. It is thus a battle of the bugs.

For contiguous buttons, the IE bug is less irritating, so place a space before the </A> tag. For the spaced button-bar however, the IE result is very ugly, so it is better to eliminate all white space immediately before and after the </A> tag – unless you want to annoy IE users of course. ;-)

Right, now we come to the bit which was turning my hair grey. Once one has inserted the above IE 5.0 kludge, it affects the display in Opera 6: the wrapping becomes unattractive as bits of coloured bar wrap without the corresponding text.

However, I discovered that if one inserts this IE 5.0 kludge, the IE 6 bleeding problem goes away! So one goes back to inserting the “wrap-triggering” space before the </A> tag, and suddenly things land on their feet.

Line height

The last point needing attention is that the use of padding on the buttons will cause them to overlap vertically after wrapping. This can be avoided by setting the line-height property to a value (e.g. 2 or 2.5) which is big enough to accommodate the padding: #navbar LI {line-height: 2}

Alternative Markup

As a final point, I'll just mention that one can also use <DIV> and <SPAN> elements instead of <UL> and <LI>. This has the advantage in older browsers that the links are displayed horizontally, just as with CSS-supporting browsers. On the other hand the markup becomes a little messier: instead of <LI> one has to write something like <SPAN class="button">, and with the IE 5 kludge one ends up with nested spans. It's up to you.

Conclusions

Once one has done all this, the button bar works well in most current and recent browsers, while degrading gracefully in IE 5.0 for Windows (slight degrading only), in older browsers such as Netscape 4, and in all browsers which do not recognise CSS.

The issues I know of are as follows:

  1. In IE 5.2 for the Mac, the result can be a mess, depending on window width. This is the only case where the issue is bad enough to affect usability. However IE for the Mac must be very nearly extinct by now.
  2. Opera 7 has a cosmetic issue: when the browser window is narrow enough to cause the button-bar to wrap, there is “ghosting” on the right-hand side. The button-bar is still perfectly usable though. Sadly Opera 8 has made the problem slightly worse instead of better.
  3. Apparently iCab had issues when I first wrote this page in 2003, but I'm not sure of the present status.

I have also been warned of problems when including the button bar in a DIV on which relative positioning has been applied - not something I've felt the need to do myself.

As this is based only on standard HTML and CSS, support can be expected to improve further in the future.

Vertical button-bars

As I said at the beginning, vertical CSS button-bars (menus), which do not need to use {display: inline}, are much easier and less vulnerable to browser bugs, since padding, border and margin on block elements are better supported. Instead one just suppresses the list bullets with {list-style: none}. As long as one uses “@import” to hide the CSS from Netscape 4, they display correctly, or degrade gracefully, in all browsers as far as I am aware.

Acknowledgements

I'd like to offer my thanks to all the comp.infosystems.www.authoring.stylesheets contributors who helped and encouraged me with (or embarrassed me into) tracking down the obscurer aspects of this work, including Matt Broughton, Nikolaos Giannopoulos, Andrew Thompson, Julián Hidalgo, Karl Smith, Andy Mabbett and anyone else I may have inadvertantly overlooked. That means this page owes its existence to contributors from six countries on four continents - truly a World Wide Web page.