Need some help?

I'm usually available for small jobs or problem solving with jQuery or css, at reasonable rates. Just get in touch.

Web Hosting

We recommend Clook for web hosting. UK based, great service and great value.

Building a css vertical expanding menu with flyouts – stage 1

This article describes how I built the menu used on this website, using just css. I didn’t want to use javascript, partly because it seemed unnecessary, partly because I didn’t understand it enough. I’ve tried to make this explanation as basic as possible, because I could have done with something like this myself a year or so ago.

What I wanted was an expanding vertical menu, where the second level menu is displayed only on the “parent” first level pages and second level pages – for example this page displays the second level “Websites” pages. Subsequently, as an addition to improve navigation, I added a “flyout” menu for the other second level pages – try hovering over “Blog” on the menu here to see what I mean.

I’ll walk through this in three stages. First I’ll create the top level menu and style it, then extend this to the second level as well, and finally cover the flyout behaviour.

OK, let’s start by creating the html, just with one level initially:

html

<div id="nav-menu">
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">Websites</a></li>
<li><a href="#">Photos</a></li>
</ul>
</div>

The menu items are list items <li> in an unordered list <ul>. I’ve used a div to hold the menu, but I could have just applied the id to the <ul> tag. So this produces, using the default styling of the browser – that is, with no css applied:

So, now to step through the css changes one at a time so it’s clear what’s happening.

First I’ll remove those bullet points on the first level menu. To do this we create a css entry like this:

css

#nav-menu ul
 {list-style-type:none}

This produces:

Next remove the indent on the text:

css

#nav-menu ul
 {list-style-type:none;
  margin:0px;
  padding:0px}

I need to set both margin and padding to 0px to cope with the different way in which different browsers render a list. Now we get this:

Now remove the underlining of the links themselves. This needs a new entry in the css:

css

#nav-menu ul
 {list-style-type:none;
  margin:0px;
  padding:0px}

#nav-menu ul a
 {text-decoration:none}

OK so far, but the links don’t look much like buttons. First I’ll put a dark grey border (hex colour #303030) on the links, which will also make it easier to see what’s happening:

css

#nav-menu ul
 {list-style-type:none;
  margin:0px;
  padding:0px}

#nav-menu ul a
{text-decoration:none;
 border: 1px solid #303030}

So now it looks like this:

Now I ’ll make all the links the same width. After initially stting the width in ems I ended up reverting to pixels as this produced the most consistent and predictable behaviour in different browsers. I used a width of 170 pixels. To get this to behave in IE6/7 it’s best added to both the ul and a elements.

css

#nav-menu ul
 {list-style-type:none;
  margin:0px;
  padding:0px;
  width:170px;
}

#nav-menu ul a
 {text-decoration:none;
  border:1px solid black;
  width:170px;
  display:block}

I’ve added two statements here, the width itself and the display:block statement which tells the browser to display the link, in this case, as a block rather than a piece of text. Now we have:

Next I’ll centre the text in the box. (As I’m English I get a bit annoyed at this point because I have to spell centre incorrectly.):

css

#nav-menu ul
 {list-style-type:none;
  margin:0px;
  padding:0px}

#nav-menu ul a
{text-decoration:none;
 border:1px solid #303030;
 width:170px;
 display:block;
 text-align:center}

Which gives me this:

This is starting to look like what I want. Now I’m going to set the font size to be a bit bigger:

css

#nav-menu ul
 {list-style-type:none;
  margin:0px;
  padding:0px}

#nav-menu ul a
{text-decoration:none;
 border:1px solid #303030;
 width:170px;
 display:block;
 text-align:center;
 font-size:14pt}

And now I’ll make the buttons a bit taller using the line-height property

css

#nav-menu ul
 {list-style-type:none;
  margin:0px;
  padding:0px}

#nav-menu ul a
{text-decoration:none;
 border:1px solid #303030;
 width:170px;
 display:block;
 text-align:center;
 font-size:14pt;
 line-height:2em}

This will centre the text vertically in the box as well:

Getting there. Now I’ll give the buttons the dark grey gradient background that gives them the ridged appearance. This is done by creating a 3 px wide image which is as high as the button, setting this as the background image and repeating the background along the x-axis (the horizontal axis). The image name is Button_top.gif, and it’s in the folder Images/Buttons. Hence:

css

#nav-menu ul
 {list-style-type:none;
  margin:0px;
  padding:0px}

#nav-menu ul a
{text-decoration:none;
 border:1px solid #303030;
 width:170px;
 display:block;
 text-align:center;
 font-size:14pt;
 line-height:2em;
 background:url(Images/Buttons/Button_top.gif) repeat-x left;}

So that last line is referring to the background image itself, repeating on the x-axis, starting from the left. Now the menu looks like this:

Finally, for the top level menu, I’ll make the text colour white and the font Arial :

css
#nav-menu ul
 {list-style-type:none;
  margin:0px;
  padding:0px}

#nav-menu ul a
{text-decoration:none;
 border:1px solid #303030;
 width:170px;
 display:block;
 text-align:center;
 font-size:14pt;
 line-height:2em;
 background:url(Images/Buttons/Button_top.gif) repeat-x left;
 font-family:Arial, Helvetica, sans-serif; color:white}

This gives us our finished top level menu, all driven by css.

Click here for Part 2

3 responses to “Building a css vertical expanding menu with flyouts – stage 1”

  1. bill meyers says:

    Thank you very much. With your tutorial I found my error.

  2. Fubu says:

    Could you be more specific on where to start adding the coding for CSS.
    Thanks

  3. Simon says:

    It shouldn’t matter where the statements go in your css file. Adding them to the end of it should be fine.

Useful? Interesting? Leave me a comment

I've yet to find a way of allowing code snippets to be pasted into Wordpress comments - so if you're trying to do this you'd be better off using the contact form.