Building a css vertical expanding menu with flyouts – stage 2

Click here for Part 1

OK, now to add the second level menu to the html. For the purposes of this I’ll add a couple of menu items under each of “Blog” and “Websites”:

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

Note that the new entries need to be enclosed within the existing <li> tags. So this gives us:

Screenshot of menu - second level added

Now the second level menu items are all showing as expected (I’ll hide them a bit later on). First let’s make them look a bit different so it’s clear which level is which.

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}

#nav-menu ul ul li a
{border:1px solid #888888;
 border-bottom: none;
 font-size:12pt;
 line-height: 1.6em;
 color:#303030;
 background-color:#a5a5a5;
 background-image:none;}

So here I’ve applied slightly different styling to the second level menu items. I’ve applied a different colour border, a different font-size, line-height and text colour, and this time I’ve applied a plain background colour (light grey #303030) instead of the background image.

A couple of things to note here. I don’t need to re-apply the width, display:block and text-align at this stage because they are inherited from the earlier declarations for #nav-menu ul a.

However, because the background-image will be inherited in the same way, and I don’t want this, I have to specifically define background-image:none for my second level menu.

The last point is a cosmetic one really. If my second level menu items have borders all round, I’ll get two borders between the menu items which looks a bit ugly, so I set no bottom border by the border-bottom:none statement.

So I now have:

Screenshot of menu - second level styled differently

Right, this looks something like what I want but I ’ve still always got the second level menu displayed. I’m going to change this so the second level is only displayed when a first level page is displayed – so I only see the “Blog 1 ” link when I’m on a blog page. First off I’ll going to hide all the second level menus.

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}

#nav-menu ul ul
{display:none} 

#nav-menu ul ul li a
{border:1px solid #888888;
 border-bottom: none;
 font-size:12pt;
 line-height: 1.6em;
 color:#303030;
 background-color:#a5a5a5;
 background-image:none;}

The browser now displays, as expected:

Screenshot of menu - second level not displayed

Here’s the clever bit. I’m now going to display the second level only on the appropriate pages. First I need to identify the pages in the html, and I can do this by assigning a class to the body tag on each page. So, on the Blog pages I assign the page a class in the body tag:

html

<body class="blog">

and similarly for the website pages:

html

<body class="web">

Note that I leave the Home Page and the Photo pages unchanged, as in this example there’s no second level pages for these:

html

<body>

Next I need to mark up the html controlling the menu with matching classes:

html

<div id="nav-menu">
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">Blog</a>
	<ul class="blog">
	<li><a href="#">Blog 1</a></li>
	<li><a href="#">Blog 2</a></li>
	</ul>
</li>
<li><a href="#">Websites</a>
	<ul class="web">
	<li><a href="#">Websites 1</a></li>
	<li><a href="#">Websites 2</a></li>
	</ul>>
</li>
<li><a href="#">Photos</a></li>
</ul>
</div>

Note that it’s the second level <ul> tags to which I assign the class. Now I can add a line to the css so that the menu items are displayed only when I want them to be. The css looks like this:

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}

#nav-menu ul ul
{display:none} 

body.blog #nav-menu ul ul.blog, 
body.web #nav-menu ul ul.web
{display:block}

#nav-menu ul ul li a
{border:1px solid #888888;
 border-bottom: none;
 font-size:12pt;
 line-height: 1.6em;
 color:#303030;
 background-color:#a5a5a5;
 background-image:none;}

To explain this, what I’m saying here is that if the page has a class of “blog” , defined by the statement body.blog and the second level menu has a class of “blog”, defined by #nav-menu ul ul.blog then the menu should be displayed (display:block). A similar statement applies to the web menu.

Now, if we look at the Home Page it looks like this:

Screenshot of menu - second level not displayed

And the Blog pages look like this:

Screenshot of menu - blog second level only displayed

And the Website pages look like this:

Screenshot of menu - websites second level only displayed

So now I have a vertical expanding menu using css only. This was my original aim, but when I was testing I thought it would aid the navigation if you could get quickly to a second level page either from the Home page or from a different page. If you’re still interested, read on:

Click here for Part 3

Useful? Interesting? Leave me a comment