It is fairly easy to use your favourite client-side language to create a dynamic menu for use on your web pages, but what if your users have web scripts disabled? This version uses pure CSS / HTML to create the same effect, so any standards-compliant browser should display your navigation menu in the same way.

I have seen this solution around on the web in a few places now, but the code below is my "spin" on the technique. Because it was non-obvious to me as a CSS beginner, I thought it worthy of inclusion on my site.

I should point out that what we are trying to achieve is a menu like the navigation menu on the left of this site, which uses no client-side code to function.

The Technique

This makes use of a couple of important facts about CSS to achieve the desired effect:

How to Do It

The first thing to do is to create your HTML menu file. This will be a simple unordered list of links structured however you like. For the purposes of the example, I will provide you with a valid HTML file. In practice, I actually use a PHP include file with the bare minimum menu. I then use a server-side include to display the menu on every page of the site. Here's the code:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
 "http://www.w3.org/TR/html4/strict.dtd">
 
<html>
 
  <head>
    <title>CSS Menu Example</title>
      <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
      <link   rel="stylesheet" type="text/css" media="screen" title="Style" href="menu.css">
  </head>
 
  <body>
    <div class="NavMenu">
      <ul>
        <li><a href="#">Home</a></li>
 
        <li><a href="#">Level 0</a>
          <ul>
            <li><a href="#">Level 1</a></li>
            <li><a href="#">Level 1</a></li>
            <li><a href="#">Level 1</a></li>
          </ul>
        </li>
 
        <li><a href="#">Level 0</a>
          <ul>
            <li><a href="#">Level 1</a></li>
            <li><a href="#">Level 1</a></li>
            <li><a href="#">Level 1</a></li>
          </ul>
        </li>
      </ul>
    </div>
  </body>
 
</html>
Get Code

You get the idea. If you plan to use SSI, you simply need to copy everything inside the "NavMenu" div element.

That's it for HTML - the rest of the menu styling comes from the StyleSheet. This leaves a great deal of flexibility and means that the content and display elements of your menu will be separated in the way that the standards intended. It means that anyone using a text browser (such as lynx / links) or anyone reading your site with accessibility software should find that your site is not restricted due to your styling.

The Basic Style Sheet

Now, create a blank CSS file in the same path as your "menu.html" file. If you are experimenting with this on your local PC, you will need to use inline CSS instead of a separate file. Initially, we will set the style of menu level 0.

/*	The Navigation Menu */
div.NavMenu
{
	margin:5px;
	float:left;
	position: fixed;
}
 
.NavMenu ul
{
	margin: 0;
	padding: 0;
	list-style: none;
	width: 150px;
}
 
.NavMenu li
{
	position: relative;
}
Get Code

So, everything will be a child of the "NavMenu" div element, allowing you to position and style the menu independently of your other page elements. If you are already familiar with CSS, the "div.NavMenu" declarations should all be fairly self-explanatory; there is a 5 pixel border to the menu, the position is fixed (so the menu does not scroll with the rest of the page) and it will appear on the left of the screen (fairly standard).

Next is the ".NavMenu ul". This is not, perhaps, such a common CSS selector. It means that any unordered list appearing in a parent element with the "NavMenu" class (in this case, our div), will have the style applied. The important parts of this element are the "list-style: none;", which removes bullets from the menu unordered list, and the width declaration, which will make each menu item the same width, so that the links look like "buttons".

We have the same idea applied to list items in the ".NavMenu li" element. The only declaration here is that list item positioning will be relative (we will come back to this in a moment).

Setting the Link Style

The next thing to do is to set the link style; currently, the unstyled links will appear in a "standard" browser as traditional underlined text entities. We need more of a "button" feel for the menu. This is where we make use of CSS subclassing. Add the following to menu.css.

.NavMenu li a
{
	display: block;
	text-decoration: none;
	color: #000000;
	background: #FFFFFF;
	padding: 5px;
	border: 1px solid #000000;
	border-left:5px solid #6495ED;
}
 
.NavMenu li a:hover
{
	background:#6495ED;
	border-left:5px solid #FFFFFF;
}
Get Code

These two blocks relate to links, within list items, contained in the "NavMenu" div. The first block here defines basic properties for links in any state (hover, normal, active, visited). The second defines a link in the mouse hover state. You should therefore bear in mind that all of the properties defined in the first block are also assumed for the second block except where specifically overridden.

The main gist of the first link block is that we remove all text decoration (underlines), set foreground and background colours and pad the text. The second link block simply changes the background colour when the mouse hovers over the link. As an extra "flourish", the border has been thickened on the left of the link. This additional border also changes colour on a mouse hover.

Showing and Hiding the Sub-Items

If you display the page with the style-sheet as it stands, you will still end up with a fairly normal-looking list, other than the styling around the links. The subitems will always be visible. What we actually want to achieve is a "flyout". This final piece of code finishes the effect.

.NavMenu li ul
{
	position: absolute;
	left: 150px;
	top: 0;
	display: none;
	border-left:1px solid #000000;
}
 
.NavMenu li:hover ul
{
	display: block;
	list-style: none;
	width: 150px;
}
Get Code

This is the clever bit. In fact, the show / hide code all takes place in two lines.

Firstly, for a list in its "normal" state, we use the descriptor "display: none", which hides the child nodes. Basically, if any list item contains a second list, this descriptor applies.

Next, for a list in its "hover" state, we use the descriptor "display: block", which shows the child node. The clever part here is that we tell the browser that this CSS formatting only applies when the parent list item is in its hover state. This is really the only "non-obvious" part of this system. The rest of the code in this section really relates to the desired horizontal offset of the submenu.

Download

The full source code for this tutorial is available in "internal" css format at the end of the full code snippet, below. Enjoy - and remember to have a play around with the code rather than using it verbatim. You'll probably end up with something that looks a lot nicer!

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
 "http://www.w3.org/TR/html4/strict.dtd">
 
<html>
 
  <head>
    <title>CSS Menu Example</title>
      <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
      <style type="text/css">
      	/*	The Navigation Menu */
		div.NavMenu
		{
			margin:5px;
			float:left;
			position: fixed;
		}
 
		.NavMenu ul
		{
			margin: 0;
			padding: 0;
			list-style: none;
			width: 150px;
		}
 
		.NavMenu li
		{
			position: relative;
		}
 
		.NavMenu li a
		{
			display: block;
			text-decoration: none;
			color: #000000;
			background: #FFFFFF;
			padding: 5px;
			border: 1px solid #000000;
			border-left:5px solid #6495ED;
		}
 
		.NavMenu li a:hover
		{
			background:#6495ED;
			border-left:5px solid #FFFFFF;
		}
 
		.NavMenu li ul
		{
			position: absolute;
			left: 150px;
			top: 0;
			display: none;
			border-left:1px solid #000000;
		}
 
		.NavMenu li:hover ul
		{
			display: block;
			list-style: none;
			width: 150px;
		}
	  </style>
  </head>
 
  <body>
    <div class="NavMenu">
      <ul>
        <li><a href="#">Home</a></li>
 
        <li><a href="#">Level 0</a>
          <ul>
            <li><a href="#">Level 1</a></li>
            <li><a href="#">Level 1</a></li>
            <li><a href="#">Level 1</a></li>
          </ul>
        </li>
 
        <li><a href="#">Level 0</a>
          <ul>
            <li><a href="#">Level 1</a></li>
            <li><a href="#">Level 1</a></li>
            <li><a href="#">Level 1</a></li>
          </ul>
        </li>
      </ul>
    </div>
  </body>
 
</html>
Get Code