Over a million developers have joined DZone.

CSS And HTML Two Level Menus Take Two

· Web Dev Zone

I ended the first part of this two part series with a working two level drop down and fly out menu using CSS and HTML. However, we did find that all was not so well when it came to, particularly, Internet Explorer 6. The aim of this part of the series then is to close the gaps and ensure that our menus will work in Firefox, Opera 9.52 and 9.6, Safari 3, Internet Explorer 6 and 7 and for good measure, we will ensure that it works with Google Chrome. So let's get started.

For me the easiest way to tackle a situation like this is to list the browsers and versions you want to, or need to, support and then work from the top down. So for this article we will use the order of the browsers as mentioned above. One important thing to note is that once the menus work in your current test browser and you move on to the next, you cannot simply forget about the previous browser. Excluding Internet Explorer, which we will target directly using conditional comments, we will more then likely need to make tweaks that might effect the browsers that has already passed the test, so we have to go back and confirm that everything is still 'a ok' in all tested browsers.

With that said let's open up the dropdown.html and flyout.html files in Firefox. No surprise here, as we saw in the previous article Firefox displays our menu exactly as expected. No that was easy enough, next up Opera 9.52. Open up the same two files. Again no surprises, let's open these files in the latest version of Opera, Opera 9.6. Everything is still as expected so on to the Safari it is. Still everything is as expected, isn't developing for the web simple and easy.

Next up is our old favourite Internet Explorer. Testing multiple versions of IE on the same machine has been a problem developers has been faced with for a long time. Evolt.org created the browser graveyard a while ago to keep copies of all of the old browsers version and also had version that you could install side by side on one machine. For the most part they worked well and is still used by many developers.

Some developers use services such as browser shots to get a screen shot of their page in various browsers on various platforms and this definitely has it's place. However, when you want to test interactive elements of a page such as these menus, this type of testing just won't do. I recently discovered IE Tester from Core Services. Even though this is still only in alpha it is already an awesome tool and my testing tool of choice when it comes to IE.

If you do not already have a copy of IETester, head over to the IETester site and download the latest version for free before continuing. After the download completes, go ahead and install your copy. The perfect environment for running IETester is Windows Vista or Windows XP with IE7 installed. Once you have IETester installed go ahead and launch the application. You will be presented with the following screen:

[img_assist|nid=5989|title=|desc=|link=none|align=none|width=500|height=303]

Next we need to open up a tab with our first version of IE that we want to test our menu in. I will work from highest to lowest here. Go ahead and click the down arrow on the 'New Tab' button and select IE 8 beta 2.

[img_assist|nid=5990|title=|desc=|link=none|align=none|width=198|height=197]

Now here we encounter one of the missing features in IETester and that is the ability to open a local file in the current tab. So in order to do this, pop open another browser and open the drop-down and fly-out HTML files in two seperate tabs. Next copy the location of the drop down menu from the address bar and paste it into the address bar of your IE8 tab and hit enter. Next open another IE8 tab, copy the location of the fly-out menu from the browser and paste it into the new tab.

Test both of these and you should find that the menus still look and function perfectly in IE8. Next step is IE7. Close the current two tabs and open up two IE 7 tabs. Again, copy and paste the location of both the menu files into the new IE7 tabs and test to see whether the menus still looks and behaves as expected.

Here is where I find another possible bug in IETester, please confirm in the comments if you experience the same, as I have IE7 installed on my computer trying to use the IE7 tabs inside IETester does not work. If I paste the location inside the address bar and hit enter, it just does nothing. I suspect this might have something to do with the security settings of IE7 where, if you launch IE7 and then try to open one of the local files you will receive the following message:

[img_assist|nid=5991|title=|desc=|link=none|align=none|width=500|height=136]

Clicking the ok button will open a new window and launch your file. So for the sake of IE7 testing I am going to launch the actual IE7 browser and not do this testing inside IETester. So, after the new window has opened and the file loaded you can go ahead and open a new tab and paste the location of the other document in here. This time IE will not display the error message and simply render your file.

If you look at the drop-down menu in IE7 everything looks fine and the menu functions as expected. Unfortunately the same cannot be said for the fly-out. Looking at this, you will see that for the two menu items that contain the fly-out's there is to much spacing between it and the previous menu item so, we have some work to do.

[img_assist|nid=5997|title=|desc=|link=none|align=none|width=224|height=161]

So what is causing this additional 1 px top padding? Well, as it turns out, when we set the two list items containing the fly-outs to position:relative IE7 added a one pixel margin to the top of each of these. So changing our second-level rule as follows fixes this:

#nav li.second-level
{
position:relative;
margin-top:-1px;
}

Now, the one problem this brings is that if you now view this in any of our other browsers again, our menu is now broken in those so, we need to find a way to tell IE to apply the -1 pixel top margin but have the other browsers ignore it. But we also need to go one step further, as IE8 rendered it correctly we also do not want IE8 to apply this margin so at this point, we need to target only IE7. How do we do this? IE conditional comments to the rescue.

Inside your CSS folder create a new file and call it ie7.css. All we currently need to add to this file is the following:

#nav li.second-level
{
margin-top:-1px;
}

P.S. Remember to remove the top margin rule from flyout.css file.

Now we need to link in our ie7.css file using the special IE conditional comments. This is then the basic syntax of IE conditional comments:

<!--[if expression]> HTML <![endif]-->

Pop open the flyout.html page and add the following after the last linked CSS file:

<!--[if IE 7]>
<link rel="stylesheet" type="text/css" href="css/ie7.css" media="screen">
<![endif]-->

Note that there should be no spaces after the initial --, ! and the last --. If you now view the page in IE7 it will display correctly, also refreshing the page in the other browsers will reveal that they are now again displaying the menu correctly. The conditional comment here is pretty self explanatory but basically, we here tell IE that if the browser version currently used is 7 then load and apply the style sheet, if not, ignore the content inside the comment block.

Another thing you may have noticed is unlike the other browsers, when you hover over the two fly-out links and the contact us links it does not show the little hand icon one is used to see when hovering over a link but instead it remains an arrow, it also does not show the title text of the anchor tag. When you move over the actual text you will see the expected result. Position relative is throwing us a curve ball again, let's fix it.

We need to ensure that both child and parent is set to position relative. Currently our list item is set to relative but the child lnk elements are not. So going back to vert_menu.css file and adding the following to the #nav li a:link, #nav li a:visited rule should solve our problem:

#nav li a:link, #nav li a:visited
{
position:relative;
}

Refresh IE7. Well it fixed our previous problem but introduced a new problem. Our final contact us link now has the large top margin back we fixed just a couple of steps back.

[img_assist|nid=5996|title=|desc=|link=none|align=none|width=222|height=155]

Let's find a way to fix this. We need to take note of the following extract of the CSS 2.1 spec to find a possible clue:

The box's position is calculated according to the normal flow (this is called the position in normal flow). Then the box is offset relative to its normal position. When a box B is relatively positioned, the position of the following box is calculated as though B were not offset.

(CSS2.1 9.3.1).

The first thing we might think, even without reading the spec is, well, give the contact us link a class and apply a -1 pixel top margin to it. In actual fact, instead of creating a new id or class we could just apply the existing second-level class to it and the problem is fixed. However, is there a better way? Or is this just one of those IE bugs that one has to apply a work around for?

One other thing that makes this rabbit hole go even deeper is if you look at the fly-out menus, they now have the same problem as the contact us link. What is worse, if you try to move from one fly-out menu item to the next and you are not quick enough, the fly-out goes away! Luckily there is a simple way to fix all of this. Delete everything from your ie7.css file and simple add the following:

#nav li
{
margin-top:-1px;
}

This takes care of the margins on all of our list items but the navigation problem on the fly-outs is still there. Add the following to the ie7.css file:

#nav li.second-level a, #nav li.second-level li
{
position:relative;
}

Refresh IE7 and everything should be good, sometimes the simplest solutions has the greatest effect.

NOTE: Even this seems to solve everything, there seems to be one new problem rearing it's head and that is that you cannot get to the 'Web Application' fly-out link. I believe this is because we are using the menu in isolation and that when used along with other content on the page this problem will go away. But to make sure, you can simply add the following to #nav, #nav ul rule in the vert_menu.css file
#nav, #nav ul
{
padding-bottom:.6em;
}

Right, so finally we can go to the last browser we need to support, our old friend IE6, which we will hopefully will be able to put to rest soon. For this, we are going back to IETester. Once you have opened IETester go ahead and open two IE6 tabs and copy and paste the location of the two files into the two seperate tabs. Does not look to bad but, looks can be deceiving. Where did the drop down and fly out go?

For IE6 there is not simple CSS solution to fix this problem and we need to sprinklle on some JavaScript to make IE sneeze out those menus for us. Now first there was Suckerfish and then came the Son of Suckerfish. However I love jQuery and was extremely pleased to see the Superfish jQuery plugin. This is then the one we will use in this article to get IE6 to play along. Let's get started.

Download Superfish from this location:
http://users.tpg.com.au/j_birch/plugins/superfish/#download

Once downloaded extract the file. Create a new folder in your current site structure called js and copy the superfish.js file into this directory. You will also need jQuery so go ahead and copy the jQuery file into your new js folder.

Now we need to link in our two JavaScript files but, we will again us conditional comments to only have these apply to IE6 as none of the browsers or version need this. Add the following to your dropdown.html file inside the head and after the styleheets.

<!--[if IE 6]>
<script src="js/jquery-1.2.6.min.js" type="text/javascript"></script>
<script src="js/superfish.js" type="text/javascript"></script>
<![endif]-->

Now go back into IETester and hit the Refresh Complete (no cache) option.

[img_assist|nid=5998|title=|desc=|link=none|align=none|width=218|height=173]

Go ahead and try out the drop down menu in the IE6 tab. Hmmmm, still not working. No worries, we simply have not called the function and we need to make a small edit to our CSS files. Let's handle the CSS first.

Open up the dropdown.css file and change the line:

#nav li:hover ul, #nav li:focus ul

to

#nav li:hover ul, #nav li:focus ul, #nav li.sfHover ul, #nav li.sfHover ul

The sfHover, ala Suckerfish, class is the class that will be added to out list items dynamically by JavaScript. All that is left is to call the Superfish function on out list items. Now create a new js file inside the js folder called ie6menufix.js and link it to the page, inside the conditional comments, as follows:

<script src="js/ie6menufix.js" type="text/javascript"></script>

NOTE: You could have added the code we will ad to this file to the head of your HTML document but, I prefer to keep things separated. Add the following to your new js file:

$(document).ready(function() {
$('ul#nav').superfish();
});

Go ahead and refresh as before. Eureka, it is working but alas, we now have to deal with IE6's CSS bugs but before we do, lets also get the fly-out's to work. First thing, add the exact same scripts with the conditional comments to the flyout.html file. Next open flyout.css and change the line:

#nav li:hover ul, #nav li:focus ul

to

#nav li:hover ul, #nav li:focus ul, #nav li.sfHover ul, #nav li.sfHover ul

Do a refresh all, no cache as before here and it works! All that is left is to fix the IE6 specific CSS problems, isn't web development fun!

Let's tackle the one with the least problems first, that being the fly-out this time. In your CSS folder create a new file called ie6.css. Then inside the IE6 conditional comments of flyout.html add the following before any of the JavaScript includes:

<link rel="stylesheet" type="text/css" href="css/ie6.css" media="screen">

Your conditional comment for dropdown.html should now resemble the following:

<!--[if IE 6]>
<link rel="stylesheet" type="text/css" href="css/ie6.css" media="screen">
<script src="js/jquery-1.2.6.min.js" type="text/javascript"></script>
<script src="js/superfish.js" type="text/javascript"></script>
<script src="js/ie6menufix.js" type="text/javascript"></script>
<![endif]-->

Now we need to add the CSS to this new file. Add the following to your ie6.css file:

#nav li
{
margin-top:-1px;
}

Problem solved! Now onto our dropdown which up to now has presented us with the least amount of problems but now seems to pose the biggest challenge. Oh yes, you can close the IE6 tab for the flyout now.

Adding the following to your ie6.css file solves some of our problem:

#nav li ul li
{
float:none;
border-top:1px solid #fff;
height:1%;
}

But, introduces something new:

[img_assist|nid=5999|title=|desc=|link=none|align=none|width=325|height=161]

Ok, so the space between the list items is not that extreme anymore but, the drop-down elements no stretch all the to right of the browser window. Now what we want. The simplest way to fix this is to give our list items an explicit width, so add the following to your ie6.css file:

#nav li ul li
{
float:none;
border-top:1px solid #fff;
height:1%;
width:175px;
}

Now, let's take care of the top border that is still to large. Now IE6 has a well known flaw that adds an extra 3 pixels to elements. Hmm, ok so that means adding the following should fix our menu:

#nav li ul li
{
float:none;
margin-top:-3px;
border-top:1px solid #fff;
height:1%;
width:175px;
}

And ideed it does! Now we have a two level drop down and flyout menu that will work in IE 6+, Opera 9.5+, Firefox 2+ as well as Safari 3+ with just a little help from jQuery and the Superfish plugin.

Answering User Questions

Following my part one entry of this series I received some questions from a user called Judy. I promissed her that I will answer her questions in this article and for the most part the above should answer them but, one other question she had involves a little more.

She asked:

"I would like however to know how to do those submenus you see on some sites, where the submenu opens up directly under the main link, usually in smaller fonts, and runs horizontally too.,usually starting back toward the left and running under adjacent links, I hope you know what I am talking about.  If you get time, can you give us all some clues about this , or refer us to other relevant websites?"


Now these are the srop down menus one sees that instead of dropping down in a veritcal fashion as ours have here, drop down and lines up in a horizontal fashion. Let's see how we can change the current drop down menu to enable this.

I first made a copy of the current dropdown.html file calling it dropdown_alt.html and also saved a copy of the dropdown.css as dropdown_alt.css. To dropdown_alt.css I changed the #nav li ul li rule as follows:

#nav li ul li
{
float:none;
float:left;
border-top:1px solid #fff;
}

Loading the new HTML file into Firefox creates the effect she was after. It also works in Opera 9.5+, Safari 3+ as well as IE 6+. I hope this answers all of your questions Judy. If however you, or anyone else, have any additional question or run into any problems please let me know by commenting on this article.

Topics:

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}