CSS Navigation

Abstract

Nowadays I code all navigation menus as simple HTML lists, because it's semantically correct and easy to work with.

In this article I will show, how such a list can be nicely laid out as a navigation menu by applying standard CSS.
Furthermore I will show client-side JavaScript code that analyzes the DOM-tree of the menu and modifies it to include more
information that can be used to further style the menu.

Applying basic style

By applying some basic CSS rules such a list can be rendered a lot nicer than that. We clearly separate menu entries with lines.
A visual feedback is given, when the user points the mouse on an item. The whole coloured area is clickable, not just the text.

Trees of nodes and leaves

Before I go on, I want to call things by their proper names. A menu hierarchy is a tree data structure. A tree consists of nodes.
Every node has a parent node and may have child nodes. If a node has no child nodes, we call it a leaf.

Tree semantics

Now the menu looks nice. But it is not very usable yet. To improve usablibity we want the following:

Highlight the currently active node.

Collapse the tree, but open everything down to the active node

Have bullets that indicate whether a menu has a submenu or not i.e. is a node or a leaf

In order to write CSS rules for the above features, we need more information about the LI elements. Every LI element can have the following
properties:

It can be active or not.

It can be a node or a leaf.

If it is a node, it can be open or closed.

Note that a closed node can never be at active (at the same time). Because when we activate a node, we automatically want it to open.

Those semantic properties should be assigned as CSS class attributes to the LI elements. Let's define the following class names.

Class

Meaning

active

The menu entry corresponds to the current page

leaf

The menu entry is a leaf in the navigation tree

open

The menu entry is a open node whose submenus are shown

closed

The menu entry is a closed node whose submenu are not shown

Analyzing the tree

The properties defined above, can be assigned automatically. We don't need to add class attributes manually. For this job we employ
JavaScript code.

The Code defines a function menu_main(id). It must be passed the id of the element that contains the navigation. In our
example, we just pass in the ID of the enclosing div tag. It's a good idea, to call this function through the onLoad
event handler of the body tag. The HTML basically looks like so:

The client-side JavaScript can of course easily be replaced by server-side logic that prints out the CSS classes on the LI elements.

Highlighting and collapsing

With all this information now available as individual classes on the LI elements, we can now write a few simple CSS rules to
highlight the current active node, and collapse everything but the active branch of the tree.

Bullets

We need three bullets: a leaf, an open node, a closed node. For each of them we want a variant when the node is active. We will then use them
as background images on the A element. If we make the active and inactive images separate image files we need to write CSS rules that match for
two classes at the same time. Actually this is possible with CSS2 like so for instance: a.leaf.active. The problem with this approach
however is, that we would need 3 * 2 = 6 individual rules and (worse) IE does not support this sort of selectors.

Fortunately there is a more elegant solution. We draw the bullets for the active and the inactive state onto the same image, but in different
positions. So here are the three bullet images on a blue background. The bullet's background is transparent.:

Leaf:
Closed:
Open:

As you can see, we have drawn the red version below the white version onto the same image. We can use the nifty background-position
CSS property to shift the background image to the right position. This way we have accomplished orthogonality for all properties. Our final
piece of CSS looks like this:

When the menu entries wrap on more than one line, just separate the two images by some more transparent space. A few hundred pixels should
be enough for most people.

Putting it all together

Now our CSS navigation is ready. We can include the same static HTML file with our navigation list into every page. On every page we just load
the JavaScript code and call it. Automagically the menu figures out the menu structure and which one is the current entry, marks them with CSS classes
and our CSS is applied by the browser's rendering engine.

Conclusion

I have shown a way to implement a navigation, that is completely based on a simple HTML list. I have shown how a client-side script can analyze
the navigation and annotate it with CSS classes. Finally I have shown how such a list can be orthogonally styled in a flexible fashion.
The CSS in this article can be used as a template whenever a vertical hierarchical navigation is needed. Tested on Mozilla 1.7.3,
Firefox 1.5, IE 6, Safari and Konqueror.