In redeveloping the Venturelab site we became increasingly aware that there was a lot of content that needed navigating extremely simply and fairly rapidly. We have so much to say and such a lot of content that the navigation of the site needed to be even more dynamic and encompassing than normal.
Each page features a sub-navigation area, which links to all the other pages within that section of the website. This is great, and works perfectly, but in order to get to, say, the FAQs page from the home page, you’d first have to go to the about page, then on to the FAQs from there. This is by no means unacceptable, but we like to go that extra step at Venturelab…
I was looking at the main menu of the site when inspiration struck. Something as common and simple as a series of dropdown menus under each meta menu item would improve the navigability and usability of the site massively. Also, they are incredibly simple to create, and here’s where I teach you how…
The concept
What a dropdown menu provides is a hierarchical overview of the subsections contained within the menu item that spawned it. Basically, it lists all the subsections within a section of a site when you hover your mouse cursor over it.
They are extremely useful in showing what a section of a site contains, and allowing you to access it from anyway else in that site, whether that be the parent page of that subsection, or a page in a different section altogether.
The markup
A lot of dropdown menus rely on bulky, extraneous markup and Javascript to work, ours willuse only the cleanest HTML and a lean 19 lines of CSS, with some lovely progressive CSS3 for good measure.
<ul id="nav">
<li>
<a href="#">Home</a>
</li>
<li>
<a href="#">About</a>
<ul>
<li><a href="#">The product</a></li>
<li><a href="#">Meet the team</a></li>
</ul>
</li>
<li>
<a href="#">Services</a>
<ul>
<li><a href="#">Sevice one</a></li>
<li><a href="#">Sevice two</a></li>
<li><a href="#">Sevice three</a></li>
<li><a href="#">Sevice four</a></li>
</ul>
</li>
<li>
<a href="#">Product</a>
<ul>
<li><a href="#">Small product (one)</a></li>
<li><a href="#">Small product (two)</a></li>
<li><a href="#">Small product (three)</a></li>
<li><a href="#">Small product (four)</a></li>
<li><a href="#">Big product (five)</a></li>
<li><a href="#">Big product (six)</a></li>
<li><a href="#">Big product (seven)</a></li>
<li><a href="#">Big product (eight)</a></li>
<li><a href="#">Enourmous product (nine)</a></li>
<li><a href="#">Enourmous product (ten)</a></li>
<li><a href="#">Enourmous product (eleven)</a></li>
</ul>
</li>
<li>
<a href="#">Contact</a>
<ul>
<li><a href="#">Out-of-hours</a></li>
<li><a href="#">Directions</a></li>
</ul>
</li>
</ul>
As you can see here the markup is simply a series of nested <ul>s. No verbose IDs/classes, no <div>s, just rich, semantic code.
The #nav <ul> contains a series of <li>s, and any that require a dropdown then contain another <ul>. Notice the dropdown <ul>s have no classes on them—this is because we use the cascade to style these, keeping our markup even cleaner.
The CSS
This is where the magic happens—we use CSS to transform a series of nested <ul>s into a smooth, easy to use, neat and self-contained dropdown menu.
/*------------------------------------*\
NAV
\*------------------------------------*/
#nav{
float:left;
width:100%;
list-style:none;
font-weight:bold;
margin-bottom:10px;
}
#nav li{
float:left;
margin-right:10px;
position:relative;
display:block;
}
#nav li a{
display:block;
padding:5px;
color:#fff;
background:#333;
text-decoration:none;
text-shadow:1px 1px 1px rgba(0,0,0,0.75); /* Text shadow to lift it a little */
-moz-border-radius:2px;
-webkit-border-radius:2px;
border-radius:2px;
}
#nav li a:hover{
color:#fff;
background:#6b0c36; /* Solid colour fall-back */
background:rgba(107,12,54,0.75); /* It'll look nice semi-transparent */
text-decoration:underline;
}
/*--- DROPDOWN ---*/
#nav ul{
list-style:none;
position:absolute;
left:-9999px; /* Hide off-screen when not needed (this is more accessible than display:none;) */
opacity:0; /* Set initial state to transparent */
-webkit-transition:0.25s linear opacity; /* Make the dropdown fade-in in Webkit */
}
#nav ul li{
padding-top:1px; /* Introducing a padding between the li and the a give the illusion spaced items */
float:none;
}
#nav ul a{
white-space:nowrap; /* Stop text wrapping and creating multi-line dropdown items */
display:block;
}
#nav li:hover ul{ /* Display the dropdown on hover */
left:0; /* Bring back on-screen when needed */
opacity:1; /* Fade to opaque */
}
#nav li:hover a{ /* Set styles for top level when dropdown is hovered */
background:#6b0c36; /* Solid colour fall-back */
background:rgba(107,12,54,0.75); /* It'll look nice semi-transparent */
text-decoration:underline;
}
#nav li:hover ul a{ /* Override some top level styles when dropdown is hovered */
text-decoration:none;
-webkit-transition:-webkit-transform 0.075s linear;
}
#nav li:hover ul li a:hover{ /* Set styles for dropdown when items are hovered */
background:#333; /* Solid colour fall-back */
background:rgba(51,51,51,0.75); /* It'll look nice semi-transparent */
text-decoration:underline;
-moz-transform:scale(1.05);
-webkit-transform:scale(1.05);
}
Just a regular horizontal navigation menu…
Right, let’s now break that down… The first section is fairly self explanatory—here we are just setting up a regular horizontal navigation menu, the same as any other. However, notice that selectors such as #nav li and #nav li a will select all list items and links in the dropdowns too. Here we’re using the cascade sensibly.
One thing of note however is applying position:relative; to the list items, this allows us to use position:absolute; on the nested <ul>s later on.
The nested lists
#nav ul{
list-style:none;
position:absolute;
left:-9999px; /* Hide off-screen when not needed (this is more accessible than display:none;) */
opacity:0; /* Set initial state to transparent */
-webkit-transition:0.25s linear opacity; /* Make the dropdown fade-in in Webkit */
}
Here we have the CSS that controls the <ul>s nested within the top level list items. Obviously we need to remove bullets with list-style:none;, then position:absolute; to position the dropdown above the list item that holds it.
A better, more accessible solution than display:none;…
The next line however is a point of interest. Usually, most people would use display:none; to hide the dropdown while it’s not being used, but due to a lot of screenreaders ignoring anything with display:none; applied, this is very inaccessible. What we do instead is take advantage of the fact the <ul> is absolutely positioned and just position it -9999px off screen when not in use.
Next up we declare opacity:0; for the hidden <ul> and then a Webkit only declaration which will smoothly fade the <ul> in from fully transparent when hovered.
#nav ul li{
padding-top:1px; /* Introducing a padding between the li and the a give the illusion spaced items */
float:none;
background:url(/img/css/dot.gif);
}
#nav ul a{
white-space:nowrap; /* Stop text wrapping and creating multi-line dropdown items */
display:block;
}
#nav li:hover ul{ /* Display the dropdown on hover */
left:0; /* Bring back on-screen when needed */
opacity:1; /* Fade to opaque */
}
Above: The 1px gap achieved by the padding-top:1px; applied to the list-item
Here we set up the default list item and link styles. Notice the padding-top:1px; on the <li>. As all the colours etc are applied to the <a>, putting a 1px padding on the <li> in effect pushes the <a>—and therefore the colour—away from the edge of the list item, giving it the illusion that they are all separated. Interestingly, IE will not recognise the layout of the <li> when hovered, closing the dropdown again. To get round this, I added a 1×1px transparent gif image as a background. Also here we remove the floats applied earlier.
Next, on #nav ul a, we apply white-space:nowrap; to prevent items wrapping onto two lines, ensuring a consistent display.
And this is where the magic happens…
The final bit of code is the bit that actually makes the dropdown appear when the list item that contains it is hovered. Now, as the :hover pseudo-class only works on the <a> element in IE6, the dropdowns won’t work in that browser. That can be alleviated by using a variety of fixes. However, as dropdowns are progressive, then we’re okay with them not working. If you do however want to get this working in IE6 then my favoured solutions is by using behaviours.
#nav li:hover a{ /* Set styles for top level when dropdown is hovered */
background:#6b0c36; /* Solid colour fall-back */
background:rgba(107,12,54,0.75); /* It'll look nice semi-transparent */
text-decoration:underline;
}
This gets tricky, but it should make sense.
This block of code here is where the hover styles come in, there’s a bit of nifty code in there which controls what we’ll call ‘persisting hover states’ on the top level item even when the user is hovering the dropdown items…
#nav li:hover a is what allows you to give the top level link a persisting hover state when hovering its ‘children’. This works by styling every link inside a list-item when that list-item is hovered. This bit gets a bit tricky but bear with me:
- The dropdown
<ul>sits inside an<li>. - If you are hovering over a link (
<a>) in a dropdown (<ul>) then you are also, at the same time, still hovering the top level list-item (<li>) as you are hovering content inside it. - Because you are technically still hovering the top level list-item, the
#nav li:hover aremains true, leaving a persisting hover style on the top level list-item’s<a>so… - …by hovering a dropdown item you are still hovering the top level list-item which means the cascade still styles all links in that list-item. Phew!
#nav li:hover ul a{ /* Override some top level styles when dropdown is hovered */
text-decoration:none;
-webkit-transition:-webkit-transform 0.075s linear;
}
Here we override certain aspects of the persisting hover state so that the dropdowns differ from the top level link. In this case we merely decide not to underline them.
We also add a touch of Webkit goodness, telling the links to transform. -webkit-transition:-webkit-transform 0.075s linear; tells Webkit to animate the -webkit-transform we apply later on in the code over 0.075 seconds with no fade-in/out. Look out for the initiation of this in the next (and final) block of CSS.
#nav li:hover ul li a:hover{ /* Set styles for dropdown when items are hovered */
background:#333; /* Solid colour fall-back */
background:rgba(51,51,51,0.75); /* It'll look nice semi-transparent */
text-decoration:underline;
-moz-transform:scale(1.05);
-webkit-transform:scale(1.05);
}
Finally, we define the styles for hovering over the individual dropdown item links. This is all really basic stuff, however there are a few items of note.
Firstly, there are the two background:; declarations. background:rgba(51,51,51,0.75); sets a moderately dark grey background on hover, which also has an opacity of 0.75. rgba is a fantastic CSS3 way of defining colours with alpha transparency (rgba = reg, green, blue, alpha) with the first three numbers representing their respective amount of each colour (between 0–255) and the final number (between 0–1) representing an amount of transparency, 0 being fully transparent, 1 being fully opaque.
Any browsers (yeah, you guessed it, IE) that don’t recognise this colour definition will revert to the old-fashioned hex value defined on the previous line, giving a solid colour fallback (R51 G51 B51 is the same as #333).
Final word
So, there you have it. A simple concept pulled off with some very lean markup and some clever CSS and progressive enhancement. It’s totally accessible, the markup is semantic and sensible and it relies on no weighty Javascript libraries to work.
Hopefully my write-up makes sense. but if anything is unclear leave a comment and one of us in the dev team will try and set you right. Or, you could just copy/paste the code and hack it apart for yourselves.
June 21st, 2010 by Harry Roberts in Web Development.





Laust said on June 21, 2010 at 11:48 am
Hi Harry
Good run-down and a nice dropdown. Just noticed a slight problem in IE8, though, as the small padding between the sub-elements sometimes closes the dropdown in that (insert-curse-here) browser. So if you move your mouse slowsly enough through the items you’ll inadvertently lose the dropdown.
However, it only occurs when you touch the gaps, with the demo-data beneath, so it might have something to fo with shifting the hover-event from the menu to those items (?).
/Laust
Simple said on June 22, 2010 at 5:59 am
I know IE6 should be dead already, but sadly, it is still in use, and li:hover it is not sported by IE6.
Garrett Winder said on June 22, 2010 at 1:41 pm
Great run-through! @simple – yeah, it’s still in use but for lots of us it’s not a big enough percentage to worry about.
Harry Roberts said on June 23, 2010 at 8:56 am
Thanks for the comments guys.
The post has been updated to more explicitly address the issues you raised, I hope that clears things up.
H
Thomas Barrasso said on June 23, 2010 at 10:35 pm
Why not consider adding RGBA for IE? http://kilianvalkhof.com/2010/css-xhtml/how-to-use-rgba-in-ie/
Harry Roberts said on June 24, 2010 at 7:59 am
Hi Thomas,
I draw the line at vendor specific prefixes, they are about as ugly as I’ll go in my code.
I don’t like the idea of using totally non-standard CSS, as it’s a complete world away from where -webkit- and -moz- etc are trying to head. If there was an -ie- prefix then maybe I would, but for now I’d rather keep my code that little bit cleaner.
Also, with the concept of progressive enhancement it doesn’t need to work in IE, so we’re okay with it not doing.
Props to Kilian though, I know him and he’s an excellent developer.
Thanks,
Harry
Zurte.com said on June 26, 2010 at 1:03 am
This i a really nice article about creating a CSS menu. Thanks!
Raiman said on July 8, 2010 at 5:21 am
This is a fantastic walkthrough for a CCS dropdown menu. It’s easy to understand, AND it creates a beautiful dropdown menu as well! I was looking all over the web and I’m really happy that I found this!
Love the site design as well. Sometimes when the presentation isn’t beautiful you don’t want to read what’s there. I’ll be browsing around this site now!
A question, though! I’m adding the menu to a wordpress blog that I’m creating, based on modifications to an existing theme. While in the demo the dropdown menu appears over text, I’m having problems with it appearing under images. Is there a simple fix for this?
Harry Roberts said on July 8, 2010 at 7:54 am
@Raiman,
Thanks for the kind words, it’s appreciated :)
I assume you’re using the menu on http://wealthdynamics.jp/ ? If so it appears to be rendering perfectly well for me and Si.
All the best,
Harry
Greg said on July 21, 2010 at 11:56 am
I love how people still love to mention ie6 when clearly it’s outdated. Let not forget to mention that the article states that there will be css3 involved, which too is not supported by ie6, nor some current browsers. The author intended on making a tutorial that shows new techniques using new technology. The fact that you checked if it would work on ie6 clearly bothers us all.