Simon Willison’s Weblog

Fun with links

Yesterday we talked about the box model. Today we’re going to put a small part of it to work, by investigating ways of styling links. Before getting stuck in, we need to talk a bit about pseudo-selectors (also known as pseudo classes). The CSS specification defines pseudo classes as “characteristics that cannot be deduced from the document tree”, but in practise the only widely implemented psuedo selectors are those that apply to links. The key psuedo selectors for links are:

  • a:link applies to normal links (but not to <a name=""> elements)
  • a:visited applies to visited links
  • a:active applies to active links (links that are currently being clicked on)
  • a:hover applies to links that the mouse is currently positioned over

It is the last of these that we shall be focusing on. One of the first and most popular effects that emerged when Javascript became popular was the image rollover, where an image (generally used as part of a site’s navigation) would change when the mouse was positioned over it. a:hover allows us to achieve a similar effect using just CSS. The most striking change is to alter the background colour, as shown in this example.

After yesterday’s discussion of the box model, it seems we would be able to achieve a lot more with this effect if links were block level elements. We can use the display: block; property to “promote” a link to block level status, which allows us to achieve all kinds of groovy effects. Consider the following HTML:

<div id="menu">
 <a href="/">Link 1</a>
 <a href="/">Link 2</a>
 <a href="/">Link 3</a>
 <a href="/">Link 4</a>
</div>

Left to its own devices, this would display as a rather uninteresting line of links. Add some CSS and we can make it look much more interesting:

div#menu {
  width: 5em;
  border: 1px solid red;
  border-bottom: none;
}

div#menu a {
  display: block;
  text-decoration: none;
  border-bottom: 1px solid red;
  background-color: white;
  color: red;
  padding: 0 0.2em;
}

div#menu a:hover {
  background-color: red;
  color: white;
}

A few things to note. Most importantly, the links inside the div are set to display: block. This causes them to “stack up” on top of each other, and also causes them to expand to be as wide as their containing box (which is why we have restricted its width to 5 ems). The menu border is set to 1px all the way round, but then the bottom border is turned off. This means that when we set a bottom border on the links themselves the very bottom link does not end up with a double border. The result of the above can be seen here.

How about horizontal navigation? That can be achieved in a similar fashion, using the float property to position the links next to each other:

div#menu a {
  display: block;
  float: left;
  width: 5em;
  padding: 0 0.2em;
  margin-right: 1em;
  text-decoration: none;
  border: 1px solid red;
  background-color: white;
  color: red;
}

div#menu a:hover {
  background-color: red;
  color: white;
}

Check out the result here. Now that the links are floated it is important they have an explicit width assigned to them. A margin-right is used to place a gap between the links. There is one caveat to this method: It is important that any following element (preferably one that spans the whole page) as clear: both; applied to it, or any text in that element will flow around the menu rather than appearing below it. This is one of the most common upsets caused by using floats, and exactly the thing the clear property is designed to solve.

There is one problem with the technique described so far: accessibility. If you run the above examples through any accessibility checker they will flag up a warning that the links in the examples are seperated only by whitespace. Try disabling CSS or viewing the examples in a non-CSS browser and you’ll see that this could definitely cause confusion—the links are displayed on a single line with only a single space between each one. A solution is at hand in the form of the humble <span> element accompanied by the display: none property:

div#menu span {
  display: none;
}
<div id="menu">
 <a href="/">Link 1</a><span> | </span>
 <a href="/">Link 2</a><span> | </span>
 <a href="/">Link 3</a><span> | </span>
 <a href="/">Link 4</a>
</div>

Here’s a demonstration of the above. Note that it’s identical to the previous example in CSS browsers; the separating pipes only show up when the CSS is not applied.

This is Fun with links by Simon Willison, posted on 27th May 2003.

Tagged ,

Next: Golden Mean

Previous: Understanding the Box Model

Previously hosted at http://simon.incutio.com/archive/2003/05/27/funWithLinks