pure CSS menus

For some time now, I've had this idea that if one could apply :hover to arbitrary elements, all kinds of possibilities would open up. Sure, we can do nifty stuff with hyperlink hovering, such as popup text and images, but to be able to apply hover styles to any element-- that would really be something.

So consider the box with the text "css/edge" near the top left of the page, or the list of "meyerweb" links on the right. If you have a browser that has advanced enough CSS2 support, you can hover over some of the links and get a popout menu. As you drill down, some of the links in those menus lead to popout submenus. And it's all driven by CSS and some nested lists. Absolutely no Javascript was used in the making of these menus.


Yes! That's what happens when you have a rendering engine (Gecko, in this case) that permits hover styles on arbitrary elements. Okay, it also has to be good at positioning, but fortunately for us, Gecko's positioning code is up to the task.

Dig into the markup and the CSS. It's all there, and it's actually a lot less complicated than you might think. In both cases, the markup for the menus is nothing more complicated than some nested ul elements. I just used id hooks on each list so that I could give each list a very different look-and-feel. Try it out! Even better, thanks to the title attribute, we can have "tooltip" expansions of the menu entries-- try it on any link in a "css/edge" submenu (in either menu).

Here's the foundation of this effect:

  li ul {display: none;} 
  li:hover > ul {display: block;} 

Sprinkle a little positioning on top of that, so that the popout menus go where you want them, and you're in business. Frost on some borders, colors, et cetera, and you're stylin'.

How about other browsers?

In other CSS-aware browsers, like Internet Explorer, you'll see the toplevel links, and they'll work just fine. The popout menus won't work, that's all. Of course, this means that the browser is downloading the contents of the complete menu, but only able to display a small part of what it downloaded. This is in some respects unfortunate, but at least the basic menu will still function. And the amount of markup involved is probably a lot fewer characters than a similar Javascript-driven menu intended to serve a similar purpose.

(And if you're grumbling that you don't see why anyone would deploy a menu system that only worked in one browser, then you should see how many Javascript menus I deal with that don't work in more than one or two browsers-- usually because they're doing browser sniffing as if this were still 1998. But I digress.)

If the browser is too old to understand CSS, or doesn't support CSS because (for example) it's a text-mode browser like Lynx, then the user will get the entire menu as a set of nested lists. No problem.

It would also be possible to construct the selectors in the CSS so that the hiding of the submenus could only be understood by advanced browsers, thus giving the complete set of nested lists to any browser that wouldn't have been able to deal with the popouts. I didn't take this step for the demo, because it cluttered up the CSS. Besides, it just didn't seem like as much fun that way.


It was Porter Glendinning who gave me the idea to use nested lists instead of hopelessly convoluted nested divs, and both Porter and Inigio Surguy devised the same basic technique independently of my efforts. Both their demos (Porter's, Inigo's) came to my attention just after I announced the first draft of this demo on css-discuss, and in both cases gave me some ideas to flesh this demo out a little more fully. Many thanks and kudos are due to both!