Suckerfish revisited – CSS/HTML dropdown menu: Barebones

by Peter

Introduction

The Suckerfish menu, first published in A List Apart in 2003, was a major achievement. The authors, Patrick Griffiths and Dan Webb, showed how to build a horizontal dropdown menu with very efficient CSS. It is often referred  to as a CSS-only menu. For browsers that didn’t support the “li:hover” (Internet Explorer – IE – 6, of course), the authors provided a JavaScript that made the menu work even there.

Markup (HTML)

A standard unordered list (<ul><li>). It has class="barmenu".

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<ul class="barmenu">
    <li><a href="#">Link 1</a></li>
    <li><a href="#">Link 2</a>
<ul>
    <li><a href="#">Link 2-1</a></li>
    <li><a href="#">Link 2-2</a></li>
    <li><a href="#">Link 2-3</a></li>
</ul>
</li>
    <li><a href="#">Link 3</a>
<ul>
    <li><a href="#">Link 3-1</a></li>
    <li><a href="#">Link 3-2</a></li>
    <li><a href="#">Link 3-3</a></li>
</ul>
</li>
</ul>

CSS (with comments)

The Suckerfish

The logic of the Suckerfish menu has since been used widely to build menus for web pages. The core of it was provided by the authors in a barebones version. The Suckerfish dropdown menu uses the following 5 rules to do the job (I have included their original comments as well):

ul { /* all lists */
    padding: 0; margin: 0; list-style: none; } (Rule S-1)
li { /* all list items */
     float: left; position: relative; width: 10em; }(Rule S-2)
li ul { /* second-level lists */ display: none;
     position: absolute; top: 1em; left: 0; }(Rule S-3)
li>ul { /* to override top and left in browsers other than IE,
  which will position to the top right of the containing li, rather
  than bottom left */ top: auto; left: auto; } (Rule S-4)
li:hover ul, li.over ul { /* lists nested under hovered list items */
     display: block; } (Rule S-5)

That’s it. Five CSS rules for a dropdown. This was a major achievement at the time it was published – neat, simple, orderly rules and very cross-browser compatible. The question is: Can it be improved on now, almost ten years later, with more standards-compatible browsers and with IE 6 more or less out of the picture? As of July 2011 IE6 is used by 2.3% of users. And IE7 is used by a little more than 4%!

Modern CSS dropdown – barebones

In the following rules you can take out the “.barmenu” if you want – I just need to use a “class” here because I have other menus and other unordered lists in this blog, so that I need to use more specific rules.

.barmenu ul, .barmenu li { /* all lists */
	padding: 0; margin: 0; list-style: none; } (Rule 1)
.barmenu li { position:relative; float:left; width: 5em;
    padding:0 0 1px; } (Rule 2)

I usually style the link element rather then the <li>, but since I don’t style I simply give the <li> a width here. This should go out when the menu is styled. The strange padding is explained below (under Rule 4).

.barmenu li ul { position:absolute; visibility:hidden;
      top:20px; left:0; }(Rule 3)

I usually use use “visibility: hidden” and “visibility: visible” to hide and unhide the dropdown. “Visibility” was introduced in CSS2 and is well supported today. I could also have hidden the dropdown outside the viewport, positioning it absolutely at -999em, which today is another standard method. Or, I could have used “display:none”. As it turns out, all the three ways of doing it encounter similar problems in IE7 and IE8.

“top” and “left” above are needed for IE7 and IE8, the modern browsers (Opera, Chrome, Firefox, and Safari) do not need them. The modern browsers seem to assume “left:0″ and a vertical offset equal to the current line height – both reasonable assumptions. IE, on the other hand, assumes 0 vertical offset and a default margin <ul> or <li> offset, which simply is odd.

.barmenu :hover > ul { visibility: visible; margin-top:-1px;
  background: #FFF; }(Rule 4)

(PS 9/23/2011: I have revised and changed .barmenu li:hover > ul to .barmenu :hover > ul.) This rule makes the child elements of a <li> visible when <li> is hovered. Note that “visibility:hidden” reputedly leads to “performance problems” in IE7 and IE8, while the modern browsers seem to handle content hidden with “visibility: hidden” quite well.

However, it also contains two “fixes” for IE7 and IE8. The first is “background: #FFF”. This is not included to give a background (I use white – #FFF – here anyway, so the menu inherits that) – it is there to make the display of the dropdown stable and scrollable in IE7. Without background the submenu appears as long as the mouse hovers over the parent menu item, but once you move the cursor down over the submenu, the submenu disappears. This is not what we want.

I have spent many hours tesing various fixes to this. The usual fixes for IE problems, such as “zoom:1″ or “height:1%” don’t work here. But background does – either a color or a background image. Omer Greenwald at webtechwise.com uses a transparent background image as a fix, and that seems to work just as well.

The other fix used here, which also seems to be required for IE7, is to make certain that the top menu and the dropdown actually “touch” one another. If there is a one pixel gap, the dropdown will disappear when you move the cursor down and over the “gap” to click the submenu items. The fix for this is to include a padding of 1px at the bottom of the <li> (Rule 2) and then use a negative margin of 1px to move the dropdown up into the top menu (Rule 4).

It is somewhat interesting to note that if you move the dropdown a little too far down – for instance “top:25px” – the problem returns.

Note that most of the fixes for IE used here are specific to a barebones menu. Once you style the menu, the dropdown is likely to actually touch the top level menu, so that problem disappears. And when you give color to the background – which you probably will – you take care of that issue too. (To the right is the list before we apply CSS and turn it into a menu.)

OK. That’s it. One rule less than the Suckerfish menu, and we don’t need any java if we don’t support the soon to be gone IE6. It works as intended in all major browsers as well as IE8 and IE7. To make it work in IE6 will require rewrites, as IE6 does not support the child selector > that I use here. It will also require JavaScript as IE6 only supports the hover property on links, not on lists and other elements.

Here’s the menu:

So that’s it. Four CSS-rules for a dropdown menu – and one of the rules a reset rule (Rule 1). If you have resets in place in your CSS, you probably don’t need it. So, three rules really. That’s all we need with modern browsers! But then, of course, lots of fixes for the older versions of Internet Explorer. What a huge waster of web designer man hours those browsers have been.

Basic styling

Usually one styles the links rather than the <li>-items. The advantage is that  by doing it this way, one increases the clickable area of the menu. The <li>-items don’t need styling – they simply adapt to the space required by the content.

.barmenu2 a { display: block; width: 5em; color: black;
  line-height: 25px; text-decoration: none; background: silver;
  text-align: center; } (Rule A)

I need to use a different class, as I display both menus here.

.barmenu2 a:hover { background: #7B7B7B; color: yellow; } (Rule B)

If you want to style the dropdown (I don’t do it here), you can use:

.barmenu2 li ul a { something .. }, and
.barmenu2 li ul a:hover { something else } (for the hover)

And that’s all. So now I can remove the various fixes (in Rules 2-4) from the barebones example. The only ones I still need are “top:25px” (adjusted to 25px as that is the height now) and “left:0″. I’ve also taken out the width in the <li>-rule:

.barmenu2 li{ position:relative; float:left; } (Rule 2)
.barmenu2 li ul { position:absolute; visibility:hidden;
    top:25px; left:0;  } (Rule 3)
.barmenu2 :hover > ul { visibility: visible; } (Rule 4)

A useful tip on styling menus with hidden dropdowns or flyouts is to simply comment those parts that hide it out and style the menu with the whole menu visible. Here that would simply mean to comment it out like so /* visbility: hidden; */ in Rule 3. When done, you simply remove the comments.

OK. Here is the menu:

So there it is with some basic styling. Now it works just fine in all browsers, including IE7 and IE8. See the demo with source and CSS.

Stay tuned for much more on menus!

Related Posts:

Leave a Comment