CSS Design and style... the possibilitiesCSS Design and style... the possibilities

CSS DropDown Menu Tutorial

CSS Menus - Fluid and Accessible - Horizontal Tutorial

Following on from the vertical tutorial, which I recommend you read first, if you haven't already, as it covers more of the Internet Explorer workarounds in depth.

..................................................

If this page or others here are any use to you and you feel like donating a few pennies for my hosting, then please feel free to....

..................................................

Horizontal CSS Dropdown and PopOut Menu

References:

To The CSS

The Horizontal version of this menu is built with the headings <h2>'s showing across the top, activating a first level drop drown when hovered over, leading to further pop-outs, on hover, where necessary. If you haven't read it yet I would try recommend the Vertical Pop-Out Menu Tutorial first as there is a lot of explanation in that which is also relevant to this menu, especially to positioning the popouts.

Firstly this time the #menu div is still our "container" only this time we want it to be 100% wide, so we could leave it as it is because it would default to this. However to properly contain the floated child lists if we also float the #menu div is will stretch to contain its floated children.

We then need to set the required dropdown width but this time it goes directly onto the <ul> elements themselves, and the need to be floated in order to appear side by side. We also still need to remove all the default padding, margins and bullets from the <ul>s the same as before.

#menu {
width: 100%;
background: #eee;
float: left;
}
#menu ul {
list-style: none;
margin: 0;
padding: 0;
width: 12em;
float: left;
}

The first stage now looks like this, showing the three lists in horizontal alignment because they're floated, the background color is only for demo to show the container actually stretching, it can be removed later.

Then we apply the required formatting to the <h2> headings and the <a> anchors, again I'm using the same formatting as the vertical menu

#menu a, #menu h2 {
font: bold 11px/16px arial, helvetica, sans-serif;
display: block;
border-width: 1px;
border-style: solid;
border-color: #ccc #888 #555 #bbb;
margin: 0;
padding: 2px 3px;
}

#menu h2 {
color: #fff;
background: #000;
text-transform: uppercase;
}

#menu a {
color: #000;
background: #efefef;
text-decoration: none;
}

#menu a:hover {
color: #a00;
background: #fff;
}

Which now shows the three, top level choices neatly in a line with all their vertical lists below them. - If it didn't did you forget I told you not to view in IE until the end!, try again in a non-IE Browser please..

Positioning the Pop-out Drops

The First level Drop Down Menus are already in the correct place, so we don't need to position then, but we need to position the children, nested lists, of these choices absolutely again, so just like the vertical version we need to make the parent <li> elements into containing blocks for these absolutely positioned children, which is doing by placing position: relative; onto the parent <li>'s and again because we are not using offset co-ordinates to actually move these <li> elements we can apply it globally.

Then we need to select all <ul> elements that have at least TWO parent <ul>'s again in order to move them over into their pop out position. This time we do not need to set the width here as we already set the width on all <ul> elements to 12em so this will take that width too by order of the cascade.

#menu li {position: relative;}

#menu ul ul ul {
position: absolute;
top: 0;
left: 100%;
}

Now the lists are all in position, view this page in a non-IE Browser for results.

However now, which is not apparent yet in these simple demo pages, we have a problem if there is text underneath this navigation bar, which there would most likely be in a real page.

Because we have left the first child list "in the flow" of the document rather than position it for pop-out purposes it is actually pushing any following text down below it. Normally in these drop down scenarios we would want it to drop down over the top of on any existing text.

We can do this by pulling it out of the flow using absolute positioning again, only this time we don't want to give it any offset co-ordinates, because we're actually happy with where it is, and just in case we'll give it a high z-index to ensure it and it's children actually do appear over the top of any positioned text that may follow.

#menu ul ul {
position: absolute;
z-index: 500;
}

Which now like this and I've now added some text in so you can see it tucks right up to the first level (heading) row.

Hiding and Revealing using :hover

First let's hide all those "drop and pop" menus using the display property.

A "Remember IE" Moment

This is where we have to get more specific with the CSS than we should have to be because of IE. We cannot use Child Selectors so we will do it longhand, it's OK, this way will still work for other browsers too.

Also due to working with an older csshover.htc file while developing these menus we became aware that IE5.x required a more specific element selector or the menus just didn't work in those browsers. The behavior file has now been updated to address this issue, so using this fix is no longer required.

Although a point to note: In our testing/development of these menus we found that leaving the CSS workaround in place improved IE's performance on larger menus. The choice is yours, I'll leave it in this demo CSS.

This time we actually do want to hide the second level menu (top choice) as we only want the <h2> heading to remain visible offering the top level choices as a dropdown, and then any further choices as popouts, so we need to target all <ul>'s that have at least ONE parent <ul> which will leaving out the heading list because it doesn't have a parent.

div#menu ul ul {
display: none;
}

Again that was the easy bit, so let's get to revealing them again.

Again the convoluted CSS to keep IE happy, this time when we hover over the first <li> which is in fact the heading too we want the child lists to appear

div#menu ul li:hover ul
{display: block;}

But again as with the vertical list this will bring back all child <ul> elements as soon as that first <li> is hovered on. So we need to add the counteracting CSS for each level we wish to target.

In this demo we require 3 levels of hover to activate child menus so we have three levels to counteract also.

div#menu ul ul,
div#menu ul li:hover ul ul,
div#menu ul ul li:hover ul ul
{display: none;}

div#menu ul li:hover ul,
div#menu ul ul li:hover ul,
div#menu ul ul ul li:hover ul
{display: block;}

the display: block; rules show the three levels being activated with the display: none; rules being entered afterwards to more specifically hide the unwanted (deeper nested) lists (counteract them).

This now shows a very nice job, well done for the compliant browsers.

Now It's IE's Time again!

This time if that last sample is viewed in IE it doesn't look so bad except for the unnecessary whitespace between the nav bar and the text, however we know the hovers are not activating so let's call the Magic Ingredient again, the csshover.htc file

body {
behavior: url(csshover.htc);
}

Now when you look at in IE, the hovers are working, but there are still a few other things still wrong with it

  1. whitespace between the list items
  2. the anchor hover background change only works of the link text itself is hovered over, it should happen on the whole block
  3. You cannot increase or decrease the size of the text
  4. The first hover is moving the list down even though we absolutely positioned it to take it out of the flow

A lot of that list is exactly the same as the problems in the vertical list, namely the font-sizing issue, the whitespace problem and the anchor block problem. So let's deal with them first in exactly the same way we did there ~ Same problems = Same Solutions.

The complete conditional CSS is the same as the vertical menu's code and looks like this:

<!--[if IE]>
<style type="text/css" media="screen">
body {
behavior: url(csshover.htc);
font-size: 100%;
}

#menu ul li {float: left; width: 100%;}
#menu ul li a {height: 1%;} 

#menu a, #menu h2 {
font: bold 0.7em/1.4em arial, helvetica, sans-serif;
}
</style>
<![endif]-->

One problem that we didn't apparently deal with is the first list is now respecting the position absolute, you'll have to take my word for it until you view the link below, but we dealt with it! The dimension (1%) on the <li> element took care of that too, IE is a strange creature at times, but once you realise that a lot of its problems are inter-related it's easier to understand that one fix often suits all.

The page, viewed in any browser is now complete!

Summary

So that's it there has been some nuances left out like background images etc.. but the basics of hover, positioning and getting it to be compatible with IE/Windows 5+, were the major requirements here.

What we have here is the bare bones of any particular style of dropdown you would like to create, background images can be used to spice it up, but most of all the HTML has remained clean throughout meaning it's very accessible to all UA's and Search Engine spiders.

The other main thing I would say is that please always develop in a non-IE environment as IE workarounds are unfortunately as necessary as CSS hacks were a couple of years ago. I hope you see that CSS driven menus are firmly within our grasp because we can work around IE quite easily and it's foibles can usually always be fixed especially when sticking to CSS2 properties.

..................................................

If this page or others here are any use to you and you feel like donating a few pennies for my hosting, then please feel free to....

..................................................

Enjoy!

«« Menu Notes and Resources | CSS Examples Index | Read Vertical Tutorial »»