Web Matters

CSS buttons

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.

When I first put together a page on this subject, achieving this was something of a challenge due to the number of bugs in common browsers. This original version is still here, but is probably of little interest now, unless you are looking for examples of how things were in the bad old days. CSS button-bars are now much more straightforward, and can be done with nice clean HTML.

Note that this page is mainly concerned with horizontal button-bars. Vertical bars are easier still.

As an aside: should one write "button bar", "button-bar" or "buttonbar"? The hive-mind of the Web seems to marginally prefer writing it as a single word, and maybe this will one day be considered correct, but stringing words together like that seems to me a rather Germanic way of doing things. The hyphenated version looks correct to me.


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.

Example spaced button-bar:

Example contiguous button-bar:

This is one of those things that is basically quite simple, but has some unexpected little problems. I actually tried three or four approaches before finding one that was satisfactory.

The basis is quite straightforward. The buttons are defined in the HTML as an unordered list of links.

  <UL class="spaced button_bar">
      <li><a href="index.html">Web Matters main page</a></li>
      <li><a href="pagemodel.html">Four-level model</a></li>
      <li><a href="zebra-tables.html">Zebra tables</a></li>
      <li><a href="contact.html">Contact me</a></li>

This way, if the page is viewed unstyled, then the buttons are still perfectly readable and usable, and if Javascript is disabled the buttons still work.

To get the buttons to run horizontally, you then use a CSS style to display the list items as an inline-block: .button_bar LI { display: inline-block; } This also means that the button-bar wraps nicely in a narrow window. (Don't use "display: inline" because each word on each button then wraps independently. You would need to attach the words on each button to each other using &nbsp; characters, and even then the wrapping works less well, with bits of colored background getting left in the wrong place.)

To get the button-bar centered on the page you need to add the following properties: .button_bar {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).

Then you apply .button_bar 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.

If you want a bar where the buttons are spaced out, all you now need to do is add the usual CSS padding, border, margin and colours. I have also applied border-radius: 0.5em; to get nicely rounded buttons in those browsers that support this CSS3 property. See my example CSS.

Inline-block has however its own problem if you want the buttons to join up as a contiguous bar. A space is left between the buttons. In the original version of this page this was solved by leaving a space at the end of each button, but this does not work with inline-block. One solution is to suppress all white-space between the links in the HTML, but this results in ugly mark-up which may easily go wrong during maintenance.

It is the intention to solve this in CSS3 with a styling option to collapse the white-space, but this is not yet generally supported. In any case there is a second problem: one wants to have separator lines between the buttons. As long as there is no wrapping, this is easily done by applying a right-border to all the buttons, plus a left border to the first button in the list, using the CSS first-child pseudo-class. But when the bar wraps, the first button on the second row has no border on the left: this is not disastrous, but not attractive either.

To fix this, I set borders on all four sides of the buttons, and apply a small negative margin to the left-hand side. This shifts the button just far enough left to cover up both the white space and the extra border on the previous button. Et voila: a nicely wrappable button-bar which is accessible and still works under all conditions (no images, no styling or no Javascript).

As far as I know this works in all current and recent browsers (I have checked it in current versions of Firefox, Opera, Chrome and Internet Explorer. )

Three-dimensional buttons

It is also possible to give buttons a 3D effect.

This is done by making the borders a little wider and choosing appropriate colours. When I worked out how to do this I was surprised how simple it was. You choose border colours which have the same hue and saturation as the background of the button, but the left and top borders have a higher luminosity (ie. they are paler) while the other two borders have a lower luminosity. This gives the illusion that the buttons are sticking up and are illuminated from the top left. You can sort out the rgb values needed in a tool as basic as MS Paint.