Adding a drop down to our image-based CSS menu

December 8, 2008 – 7:40 pm

Drop down menus are all the rage!

CSS drop down menus have been done before, so rather than reinvent the wheel, let’s use a tried-and-true CSS drop down menu method by Patrick Griffiths and Dan Webb aptly named the “Suckerfish Dropdown.” You can read more about it at A List Apart, a site with oodles and even-more-oodley-oodles of web design articles.

What we’re going to be doing is integrating my previous image-based CSS menu with the Suckerfish drop down. It’s pretty easy. As always, first, the markup:

<ul id="menu">
		<li id="selected" class="home"><a href="#">Home</a></li>
		<li class="locations"><a href="#">Locations</a>
			<ul>
				<li><a href="#">Americas</a></li>
				<li><a href="#">Asia</a></li>
				<li><a href="#">Europe</a></li>
				<li><a href="#">Africa</a></li>
				<li><a href="#">Oceania</a></li>
			</ul>
		</li>
		<li class="about"><a href="#">About Us</a>
			<ul>
				<li><a href="#">Company Profile</a></li>
				<li><a href="#">Investors</a></li>
			</ul>
		</li>
		<li class="contact"><a href="#">Contact Us</a>
			<ul>
				<li><a href="#">Online</a></li>
				<li><a href="#">Phone</a></li>
			</ul>
		</li>
	</ul>

As you can see, the markup is identical to the image-based menu markup with the addition of a nested unordered list. That nested unordered list will be our drop down. It’s neater, more semantically relevant, and shorter than any Javascript solution you can think of, that’s for sure! Next up, the CSS:

html {margin: 0; padding: 0;}
body {
	margin: 0;
	font-family: Arial;
	background-color: white;
	font-size: .75em;
	color: #333;
}
a:link {color: white; text-decoration: none; font-weight: bold;}
a:hover {color: #87acee;}

ul#menu {
	list-style: none;
	margin: 0;
	padding: 10px;
	height: 25px;
	background: #303136;
}
ul#menu li {
	float: left;
	display: inline;
	height: 25px;
	margin: 0 10px;

}
ul#menu li a {
	display: block;
	height: 25px;
	text-indent: -999em;
}

.home a {background: url(images/menu_home.png) 0 0 no-repeat; width: 67px;}
.locations a {background: url(images/menu_locations.png) 0 0 no-repeat; width: 119px;}
.about a {background: url(images/menu_about.png) 0 0 no-repeat; width: 115px;}
.contact a {background: url(images/menu_contact.png) 0 0 no-repeat; width: 136px;}
.home a:hover, ul#menu li.locations a:hover,
.about a:hover, ul#menu li.contact a:hover {background-position: bottom left;}

ul#menu li#selected a {background-position: bottom left;}

/*Drop downs*/

ul#menu li ul li a {
	background-image: none;
	text-indent: 0;
	padding: 0 0 0 25px;
	height: auto;
	width: auto;
}
ul#menu li ul li {
	float: none;
	height: auto;
	display: block;
	margin: 0 0 10px 0;
}
ul#menu li ul li a:hover {
	background: url(images/pointer.png) 0 center no-repeat;
}

ul#menu li ul {
	display: none;
	position: absolute;
	top: 1em;
	width: 179px;
	padding: 15px 10px 0 10px;
	background: url(images/dropdown.png) left bottom no-repeat;
	left: 0;
	margin: 0;
}

ul#menu li>ul {
	top: auto;
	left: auto;
}

ul#menu li:hover ul, ul#menu li.over ul {
	display: block;
	left: auto;
}
*:first-child+html ul#menu li:hover ul,
*:first-child+html ul#menu li.over ul {
	position: static;
}

Let’s start breaking that down a little. Everything above the /*Drop downs*/ comment is from this previous article, so read that one if you’d like an explanation of what’s going on there.

The first snippet we’ll take a look at is the following:

ul#menu li ul li a {
	background-image: none;
	text-indent: 0;
	padding: 0 0 0 25px;
	height: auto;
	width: auto;
}
ul#menu li ul li {
	float: none;
	height: auto;
	display: block;
	margin: 0 0 10px 0;
}
ul#menu li ul li a:hover {
	background: url(images/pointer.png) 0 center no-repeat;
}

What we’re doing here is resetting the properties set previously for the top-order unordered list. We’re wiping the background-image on the anchor which was used for the menu item image, resetting the text’s indent that took care of hiding plain text from the viewer, and resetting the height and width properties. Next, for the list item itself we’re removing the float property we previously used to simulate an inline list, resetting the height property, and adding some margins to the bottom just to space things out a bit.

Also, we’re adding in a little arrow pointing to the link you’re hovering. I guess I did that just because we can.

Next up is the drop down box itself:

ul#menu li ul {
	display: none;
	position: absolute;
	top: 1em;
	width: 179px;
	padding: 15px 10px 0 10px;
	background: url(images/dropdown.png) left bottom no-repeat;
	left: 0;
	margin: 0;
}

ul#menu li>ul {
	top: auto;
	left: auto;
}

This is where Suckerfish really comes in. What’s happening here is the drop down box is being hidden via display: none; and reset to an absolute position right below its list parent. The rounded corner is a simple background:

Just place it on that nested unordered list attached to the BOTTOM of the element and it’ll resize itself accordingly, provided the drop down itself isn’t taller than the image (in which case you can make the image larger yourself), keeping the rounded corners at the bottom of the drop down.

To bring up the drop down menu when a user hovers over the menu item, that’s where the rest comes in:

ul#menu li:hover ul, ul#menu li.over ul {
	display: block;
	left: auto;
}
*:first-child+html ul#menu li:hover ul,
*:first-child+html ul#menu li.over ul {
	position: static;
}

The reason for the “ul#menu li.over ul” is simple: IE6 doesn’t play nice with pseudo-classes. :hover will only work on anchors and nothing more. To remedy that, use the following snippet of Javascript for IE6:

startList = function() {
	if (document.all&&document.getElementById) {
		navRoot = document.getElementById("menu");
		for (i=0; i<navRoot.childNodes.length; i++) {
			node = navRoot.childNodes[i];
			if (node.nodeName=="LI") {
				node.onmouseover=function() {
					this.className+=" over";
				}
				node.onmouseout=function() {
					this.className=this.className.replace(" over", "");
				}
			}
		}
	}
}
window.onload=startList;

This will add the “over” class to LI nodes within the “menu” ul, and remove them on mouse outs. While other compliant browsers will just simply use the li:hover method, IE6 will instead attach the “over” class which has the CSS property of the li:hover method, in effect giving it the same outcome.

View the drop down menu

That’s all it takes.
UPDATE: Thanks John for pointing out the IE error. I’ve fixed it in the post, but the changes made were adding “left: auto;” to “ul#menu li:hover ul, ul#menu li.over ul {}” to set the position on hover, and also “margin: 0;” to “ul#menu li ul {}” to reset the margins on IE.

  1. 15 Responses to “Adding a drop down to our image-based CSS menu”

  2. great article, thank you

    By John on Dec 23, 2008

  3. would it be much harder to make the drop down submenu items images as well?

    By John on Dec 23, 2008

  4. Pretty simple, really. Just use the same technique used to place images on the root list items. For instance, in the menu example linked above you would have remove the “ul#menu li ul li a” snippet entirely, give a new class to your nested list items which will be images, and add the background/width/height properties to the new class similar to home, locations, about, etc.

    Let me know if you need any help with that and I can post up an example.

    By Orlando on Dec 23, 2008

  5. You rock Orlando, thanks for the response. I’m about to take a vacation and will implement this in a couple weeks.

    By John on Dec 23, 2008

  6. Alright, I’m implementing this concept into a site redesign and I’ve hit a bug. Everything works except in IE6 the dropdown appears at the top left of the container and not below the menu item. I appreciate any suggestions: http://www.newsite.navajocompany.com

    Thanks,
    John Cozen

    By John on Jan 7, 2009

  7. Thanks for pointing that out, I missed a couple of little things when writing this, but I’ve fixed it now:

    “left: auto;” to “ul#menu li:hover ul, ul#menu li.over ul {}” to set the position on hover

    “margin: 0;” to “ul#menu li ul {}” to reset the margins on IE.

    By Orlando on Jan 7, 2009

  8. Thanks Orlando. The IE6 implementation is still giving me problems: The dropdowns are appearing over the menu item instead of below it (adding a margin messes up the Firefox rendering) and the mouseover color change done through a background image shift isn’t happening on the main menu items. Check it out, if you can (I so owe you a beer): http://www.newsite.navajocompany.com

    Thanks,
    John Cozen

    By John on Jan 7, 2009

  9. Remove the “top: 1em;” from “ul#menu li ul”

    Also, remember that at any point you have something that looks fine on other browsers but not IE6, use the IE6 CSS conditional to target just that, unless you’re using another stylesheet for IE6.

    #content {margin: 10px 0;}

    Turns into:

    * html #content {margin: 5px 0;}

    As far as the hover states, IE6 is very picky, so instead of using “.portfolio”ul#menu li.portfolio a:hover”, be a little more robust by declaring “ul#menu li.portfolio ul li.branding a:hover” etc. to cover the nested elements.

    By Orlando on Jan 10, 2009

  10. cool thanks O!

    By John on Jan 15, 2009

  11. Any idea how I can get the drop down to stay open when the user reaches the next page? here’s what I’ve done so far http://newsite.navajocompany.com/
    respect,
    J

    By john on Jan 29, 2009

  12. That’s pretty straightforward. Just create an ID in your CSS with the set position like so:

    ul#menu li#menuSelected ul {
    display: block;
    left: auto;
    position: static;
    }

    And then in your XHTML add in the ID to the list item that’s selected for each page.

    By Orlando on Jan 29, 2009

  13. Nice, but then it will remain dropped down even when another menu item is moused over, do you know the code to hide this dropdown when another menu item is moused over? Thanks for answering my questions.

    By john on Jan 29, 2009

  14. Could you post an example with the sub menu items as an image??? It would be greatly appreciated.

    By Chris on Mar 23, 2009

  15. Very nice script. For some reason when I set this up, and click on a link, all the formatting of the links on the page lose their CSS formatting (links turn to purple and underlined). This happens in firefox, ie, and chrome. Any idea why?

    By Jonathan on Jan 13, 2010

  16. Nice Tutorial and yes Jonathan’s comment is true. and also it would also make sense if Chris comments can be guided also here.

    Chris”
    Could you post an example with the sub menu items as an image??? It would be greatly appreciated.

    Jonathan”
    For some reason when I set this up, and click on a link, all the formatting of the links on the page lose their CSS formatting (links turn to purple and underlined). This happens in firefox, ie, and chrome. Any idea why?

    By Bryan on Feb 25, 2010

Post a Comment