The Right Way to Make a Dropdown Menu

Good and bad usability in menu navigation

There’s been a lot talk on SitePoint recently about dropdown menus, and not all of it entirely accurate. So I felt the need to chip-in and set the record straight on matters of best-practice, when it comes to JavaScript menus in all their forms.

First, let’s look at the key issues that impact on good usability:

  • mouseover-driven menu should have timers that delay their opening and closing. Open-timers mean that casual mouse movement doesn’t trigger menus when they’re unwanted. Close-timers mean that if your mouse momentarily slips-off or moves outside a menu, it doesn’t close abrubtly. And a synchronised combination of the two means that you can move your mouse from one link to another without triggering other menus as you pass over intervening links
  • menus should be able to reposition on-the-fly, so that if they approach or go over the edge of the window, they shift or invert position to avoid this
  • menus must be navigable by keyboard actions alone. Being able to tab through the links and have child-menus open sequentially is acceptable; being able to navigate with the arrow keys is ideal

Now those three things together make the difference between a menu that is functionally useable, and a menu that is disastrously unuseable and a nightmare for users to deal with. All three of these things need scripting to implement, and that brings me onto the next crucial questions of implementation and fallback content:

  • the top-level links of a menu should link to pages which provide access to all the same content, so that everything which was accessible from the menu is also accessible without it. The top-level links are the core content of a menu; the submenus are a progressive enhancement
  • if scripting is not available, menus cannot be made decently useable, and therefore should not work at all — do not use pure-CSS menu triggers

Pure CSS menus are an interesting proof of concept, but that’s all they are. Eric Meyer’s invention of them led the way to our re-thinking how menus should be built in the first place (before then, menus were all built with endless reams of document.written tables and divs; Eric showed how a semantic structure could be converted into a menu), but in of themseleves they are not suitable for real-world production use.

We also need to consider exactly how the show/hide mechanism of a menu should be implemented, in order to ensure accessibility to browser-based screenreaders:

  • menus should not be hidden with display, visibility, overflow or clip, as doing so also hides them from browser-based screenreaders. The correct approach is to use absolute positioning with a large negative left offset (so-called offleft positioning), which moves them off the screen and hence apparently invisible to sighted users, but does not remove them from the rendered output and therefore doesn’t affect assistive devices

Finally, there are details of the content of menus themselves, and the finer points of design that make for a better user experience:

  • a dropdown menu is not a sitemap; it should not link to every page of a site
  • a single menu shoud not contain more links than can fit above the fold and should not require the user to scroll
  • the menu links, or preferably the entire menu structure, should scale with font size
  • the rollover state of menu links should persist down the tree, so that a user can see at a glance the path through the structure to where they are now

Before I finish, I’ll make one more point about styles and types of menu. So-called mega menus are not different from what we know as dropdown menus. They have different content and styling in the submenus, and that’s all. Jakob Neilson’s recent piece on the subject has muddied the water by implying that this type of menu is inherently more useable and accessible, but that simply isn’t true. To prove his point he’s comparing aspects of good mega menus with aspects of bad conventional dropdown menus, which is not a fair or scientific comparison, because he’s not comparing like with like. His arguments fall flat when you compare with a well implemented dropdown.

In this short post I hope I’ve clarified what it takes to make a menu, that is useable, accessible, and built with the principles of progressive enhancement in mind. And to illustrate, here are two demos that exemplify all of these points:

You can also download both examples

These menus, incidentally, are straight out of SitePoint’s JavaScript Anthology, and are fully documented in Chapters 15 and 16, which as you’d probably guess, I wrote!

Win an Annual Membership to Learnable,

SitePoint's Learning Platform

  • Damian Edwards

    While your arguments are compelling, the sample menus you link to are not without fault. For example, in FF3 I was able to very simply get the rollover state highlighting to fail down the tree (all nodes were highlighted except the parent of the leaf node).

    This, I’ve found, is the inherent problem with JS menus, in that the JS eventing system in browsers is no where near as reliable or responsive as the CSS hover detection facility. It’s generally all too easy to not have the required DOM mouse events fire when the mouse is moved very quickly over your elements.

    Of course I’m happy to be proven wrong :)

  • Damian Edwards

    Similarly, try navigating the sample menu with the arrow keys to a leaf node, note that the rollover state is not highlighted in this use case. Then, with that leaf node selected, hover over one of its siblings with the mouse and then move the mouse off again. The whole menu disappears, ignoring the fact I had selected something with the arrow keys. Finally, hit the tab key and the whole menu structure appears again with the next sibling of the previously selected leaf node now active. I’m not sure that’s very intuitive.

  • http://www.clanspace.com.au Robbo89

    Keyboard navigations isn’t working for me.

    This is something that I have needed for a while. I usually use either CSS dropdowns or JS ones that act like CSS dropdowns.

    I disagree on making the dropdowns not work when scripting isn’t available. CSS is better then nothing imo.

    I’ll be following these guidlines for now on.

  • http://metaldenver.com Jack Rugile

    James,
    Thank you for this. Ya know, I am new to web design and drop down menus have always scared me. I felt that they always had to be done with some sort of scripting and for some reason I got in my head that anything other than HTML or CSS would be bad for accessibility and SEO. Not to mention, I don’t know anything other than HTML, CSS, and some basic PHP :)
    I will definitely be checking all of these bullet points next time I make a drop down menu. However, I haven’t had much need for them so far because most of my sites are relatively small. Thanks for the article!
    – Jack Rugile

  • http://www.brothercake.com/ brothercake

    @Robbo89 – my point precisely is that CSS isn’t better than nothing, it’s worse than nothing. Would you rather struggle and fight to get through an awkward menu that constantly flickers open and closed and won’t do what you want, or would you rather just click a link once and get where you want?

    Which browser are you using that the keyboard navigation isn’t working in?

    @Jack – yeah a lot of people make that assumption at first, but properly implemented JavaScript that progressively enhances static HTML is no barrier to accessibility or SEO. The menus here are based on simple structures, which appear to a robot just like regular links.

  • http://www.clanspace.com.au Robbo89

    @brothercake – I still disagree that it is worse. In some situations I would agree but then others I disagree. Some sites also need those links and thus must have the CSS menu. I do agree that there are a lot of crappy menus out there.

    With the examples I got the keys to work when I could TAB to them which was annoying but thought they should work after pressing them when hovering or something? Maybe I misunderstood the part about key navigation.

  • frozenmyst

    This is close to perfection, but shouldn’t a dropdown menu work even if javascript is disabled, at least for modern browsers ?

  • wattsa

    on IE7 the keyboard navigation only works if the main browser window is clicked. If your focus is still on the address bar, then that is where your keyboard actions are happening.

  • http://www.tibobeijen.nl Tybe-O

    Nice article and good to see the timeout point being mentioned! A real pain if menu’s don’t have that, especially with limited item-heights.

    @frozenmyst – The only way of achieving that would be css-based dropdowns, with al the disadvantages they have. The accessibility issue is addressed by stating that top-level menu-items should be links to pages containing all the sub-links.

    As for the hiding mechanisms, what differentiates css visibility from css offset with regard to readibility by assistive devices? Aren’t both either visible (no css) or invisible (css)?

  • http://www.webflowdesign.co.uk Rob_D

    Great stuff – it always bugs me when menus collapse when I move a single pixel away from an element.

    Now I’m wondering if it’s possible to increase the size of menu elements with transparent areas so that the cursor is actually hovering over that element even though it doesn’t look like it. Would that be a good thing to do? I guess the difficulty would be where they overlap.

    Of course, timeout built into CSS would be ideal.

  • frozenmyst

    @Tybe-O:
    The mechanism of showing/hiding submenus can be achieved using “li:hover ul” for css based version; and using “li.hover ul” for javascript based version. There are no big differences between the two except for timers and positioning of sub-submenus.

    At leat for a 2 levels menu, I would recommend making the menu work without javascript. Users surfing with NoScript (for example) would benefit from this.

    The same applies to flash objects loaded with javascript. In this case, I find it useless since IE doesn’t need anymore a click to activate a flash objet.

    Javascript-Only websites is a bad trend, imho.

  • Joonas

    I can’t believe the following: “mouseover-driven menu should have timers that delay their opening and closing.”

    Am I the only one who’s irritated by having to wait the menu to open? Quick operation is the advantage of CSS menus, IMHO.

  • palgrave

    Some day I’ll learn that if you root around in sitepoint first, it can save you 3 hours work.

    Thanks James.

  • http://www.jasonbatten.com NetNerd85

    Some day I’ll learn that if you root around in sitepoint first, it can save you 3 hours work.

    you can also get a book deal. zing!

  • http://www.lunadesign.org awasson

    Great article James… And timely. Thanks!

    I’ve used several dropdown menus over the years but have avoided them if at all possible. That said, sometimes they are the right tool for the job. In fact, I’m just about to design a cascading dropdown menu for a new site today :)

    I absolutely agree with the first three points and the rest of the article is good to keep in mind too. We’ve come such a long way since the early days of HierMenus eh?

    Cheers,
    Andrew

  • CSU-Bill

    @Brothercake,

    I have seen and am currently working on using a pure CSS drop-down menu that does not flicker. If you want to see it, visit http://www.grc.com/menudemo.htm and you can also read the information about the menu. I am trying to add another level so that it matches my current menu.

  • http://www.lunadesign.org awasson

    [off topic]
    Hmmm CSU-Bill….
    Now how are you going to use a CSS based menu with an SBC6120?

  • Aarem

    So-called “mega menus” are not different from what we know as dropdown menus.

    Yes, this had me confused, as I couldn’t see any essential difference. Thanks for clearing that up.

    As for pure CSS menus, I don’t see what is wrong with them. I take the point about timers, but I don’t see this as a huge issue, but rather a minor improvement.

    I’m also not convinced that display: none on submenus is a bad thing. I have my doubts about dropdowns per se, and I feel like I’m doing sight-imparied surfers a favor by just giving them a simple link to follow. Perhaps it shouldn’t be up to me to decide that…(?)

  • http://www.brothercake.com/ brothercake

    @CSU-Bill – as much as I respect the effort you’ve gone to here, you’re making them work in IE by creating an invalid DOM. I can’t really approve of that. They also do still flicker quite badly, and have the issue that when you move your mouse from a link in one menu to a link in a child menu, you can’t pass over intervening links without triggering a different menu – very frustrating.

    To those who are convinced that pure CSS menus are better than nothing, with respect, I don’t think you’re considering the users. You, who are technically savvy, know that you need your mouse movement to be precise to make it work, but the average user doesn’t know this. If you want a more pertinent example, imagine trying to use a pure CSS menu with a hand tremor. You can simulate this yourself by shaking your hand slightly as you move. It’s so hard, and so frustrating .. it really is worse than nothing. Timers are not just sugar on top, they’re absolutely essential to make a useable experience.

    It’s important to understand that accessibility does not mean that everything is available to everyone all the time. Accessibility is about equivalency, not equality. It’s important that all parts of a site should be accessible if scripting is not available, but that doesn’t mean that exactly the same interface should be used. You can provide a different route to the same end result, and in this case, that’s a better thing to do.

    Having a transparent buffer area around the menu would help in one aspect – it would help with menus not closing prematurely – but it wouldn’t help with the other uses for timers.

    Regarding the issue with display and visibility – the problem with that is (depending on how you look at it) a bug or a feature of the way browser-based screenreaders work. Most browser-based readers (of which the most common in current use are JAWS and Window Eyes, both of which have this behavior) cannot see content which is not rendered. They’re not (for the most part) source-code readers, they’re *screen* readers – they read the screen – they can only read what you can see.

    To roughly analogise, imagine that you’re viewing a webpage and reading it out to someone over the phone. You cant tell them that there’s a hidden menu there, because you can’t see it either.

    The technique of offleft positioning avoids this issue (and breaks my analogy .. but it was just an analogy!). If you keep a menu visible but position it off the screen, the browser still has to render it, it’s just that it’s outside the viewport. So to a browser based screenreader, the menu is there just as though it was completely visible.

    The problem with this approach is that content like this can still be navigated to with the keyboard. Which is why it’s important that anything which is hidden in this way must become fully visible again whenever something inside it receives the keyboard focus.

    @Robbo89 – you thought they should work when hovering and pressing a button? I think you’re misunderstanding keyboard navigation. How do you hover with the keyboard? You can tab onto the structure, and then you can press the arrow keys to move around (or you can keep tabbing). How else would it work?

  • http://www.sinthuxdesigns.com sinthux

    Thank you for making a point to show how ridiculous that whole ‘mega menu’ post was.

    However, I think the examples you’ve given are bad choices. I’m pretty against overlaying the sub-menus, and it really makes no sense to do so. It may be easier to avoid usability issues by coding it this way, but it just makes a menu feel cluttered and confusing when you overlay the sub-menus on top of each other on their hovered state.

    Here’s an example of good positioning of sub-menus in their hovered state: http://www.elegantthemes.com/preview/ColdStone/

  • http://www.sinthuxdesigns.com sinthux

    @Aarem

    The website navigation is one thing that’s guaranteed to be on every page. Thus it’s the most important part of the design. If you go cheap on the menu, you’re doing a big discredit to the design/website. Web design is all about being user friendly, and making the experience as easy as possible. By doing what this article explains, you’ll be making it less likely that a user will have any problems with navigating through the menu.

    First impressions are everything!

  • http://www.brothercake.com/ brothercake

    The overlay doesn’t affect usability, it was just a design choice, because i happen to think it looks nice. I understand your preference – each to their own :)

  • http://www.brothercake.com/ brothercake

    Incidentally, it was not my intention to critisize any of the other bloggers here at sitepoint, and my apologies if it came across that way. The mega-menus, as a design trend, may well be all the rage over the next few months. If I were to level specific criticism in this case, it would be at Jakob Neilson for confusing the issue on a technical level.

  • http://www.brothercake.com/ brothercake

    @Damien – it’s hardly a fair test to use keyboard and mouse together. Keyboard users won’t be doing that. I did consider when i wrote it that there might be conflicts of this kind, but i didn’t spend time fixing them (and they can be fixed) because in practise almost nobody is going to do that.

    It’s true that JS can fail to detect events if they happen too quickly, but well, fair enough – nothing’s perfect. As with your mouse/keyboard test – okay, if you try hard enough you can make it fai, but can you honestly say this is a fair test of real-world conditions? Or are you just trying to break it to prove that you can?

    The links have pure CSS colored rollovers as well as the JS scripted state, so if they fail to show up that’s an issue with precedence, not scripting.

    @Joonas – you may not be the only one, but you’re definitely a minority. And in any case, please remember that there’s a difference between preference and need. You may *prefer* faster responses, but other people *need* buffered reponses; need is always more important.

  • http://www.tibobeijen.nl Tybe-O

    @brothercake – thansk for the heads-up on viewport reading of screen-readers.

    Regarding mouseover-driven menu should have timers that delay their opening and closing.. I think delaying on opening is less important for horizontal menus (menus that fold down). For sidewards extending it becomes more important as the user has to move the pointer through a much more narrow area to enterthe right submenu.

  • Florent V.

    Thanks for this article, James. I was wondering if there was decent JavaScript scripts that would handle the hover detection, and I then realized that the script I have used in a number of occasions, Superfish (a jQuery plugin), can use the hoverIntent jQuery plugin to manage that.

    I remain a bit doubtful of double-horizontal dynamic menus where the risk of tracing diagonals with the mouse pointer is very high (see lemonde.fr, for instance). hoverIntent or a similar solution may help reduce the problem, but I still think that in some cases using the click on first-level items is a better choice for displaying submenus. I guess for a specific project both solutions should have to be tested.

    Anyway, Superfish + hoverIntent = decent solution, if you’re using jQuery.

    A last note: I just noticed that the applications drop-down menus in OS X use a short delay, when you hover a second-level item, before displaying the third-level options. (For instance, in Firefox, see Display » Character encoding » …) If I remember correctly, other OSs behave like that too. I’ve sometimes found that the delay was frustrating, but now I realize that when using standard applications menus my mouse pointer happen to do diagonals a lot. Without the delay, it would be a nightmare.

  • http://www.brothercake.com/ brothercake

    Absolutely :)

    And for comparison, try the menus you get if you make folders in IE8’s bookmarks toolbar, which doesn’t do that .. and it is, intensely frustrating!

  • Damian Edwards

    Sure it’s probably an edge case, but I can’t believe I’m the only person in the world to use both my mouse and keyboard when exploring web pages, including their menus. Not trying to be difficult, just pointing out that the JavaScript approach has its flaws too (and if I were one of the testers from the project I’m currently working on, no doubt I’d be raising a bug now ;)

    Anyway, your article has prompted me to ensure we get some more objective testing by less technical users for the basic CSS menu on our current project, so thank you. If the feedback is that it’s annoying to use, I’ll be coming back here to check out the JavaScript menu samples a bit more closely.

  • Stevie D

    my point precisely is that CSS isn’t better than nothing, it’s worse than nothing. Would you rather struggle and fight to get through an awkward menu that constantly flickers open and closed and won’t do what you want, or would you rather just click a link once and get where you want?

    I disagree. I don’t generally have any difficulty using pure CSS menus, and find them much quicker than the two or three clickthroughs that would be necessary otherwise. Yes, the Javascript addons can be helpful for some people, but to claim that a pure CSS menu will cause everyone to desert your website instantly and a plague of locusts to be visited on your home is a bit over the top!

    Plenty of websites do use pure CSS menus, or even Javascript-driven menus that don’t include any latency, and don’t seem to be losing all customers as a result. There are clearly plenty of people who are happy using them, or these sites would have folded long ago.

    The set-up that I like, which can be done with pure CSS and is perfectly accessible to IE6 and keyboard users alike without any Javascript necessary (although there’s no reason not to enhance the usability with JS if you want to!) is, very simply, this:
    * make each menu item that has a submenu under it into a clickable link to a ‘front page’ for that area.
    * show the submenu(s) relevant to the current page as a static list under the top-level list – as well as allowing drop-downs from other menu items.
    This can easily be achieved through CSS by matching ids on the body and list item elements.

    This means that anyone who is unable or disinclined to use the drop-down menus for whatever reason can navigate through the pages, and because the relevant submenu appears as a static list they can drill down to the detail that way.

  • http://www.brothercake.com/ brothercake

    Mate, I never made anything like as melodramatic a claim! And I repeat what i’ve said in other comments – you may find such menus acceptable to use, but you’re in a minority of tech-literate and (if I can use the phrase) “interface-literate” people. You know how a menu is supposed to behave, what will make it fail, and where its quirks are. Most people don’t know this.

    The fact that so many sites use appallingly bad menus and continue to retain customers is not evidence that the menus are okay, it’s evidence of something else entirely, something that user testing shows time and time again – that people will fight their way through any interface, however difficult it is to use, if they’re suitably motivated by the end result. Look at how many people use MS Word, despite it having one of the most obtuse and convoluted interfaces ever designed – they do it because the software does something they need, and they simply accept the bad interface as a fact of life.

  • Tarh

    I don’t mind using a Javascript menu as long as the developer provides a fallback; I would refuse to allow a site to run Javascript for something as useless as a quick navigation system.

  • http://www.brothercake.com/ brothercake

    @Damien – You know I’d be fascinated to know actually, how many people do use the web with the mouse and keyboard combined. It’s one of those things I’ve never thought it worth scripting before because I didnt think it would actually happen, but hearing you say that you do it regularly I’m not so sure anymore.

    Food for thought :)

    btw – dunno why these posts aren’t coming through in the same order i’m getting emails about them – I suspect that the emails are in the right order, and the posts are in the wrong order, some timezone weirdness perhaps. But you posted your last comment after Tarh’s comment, right, even though in the thread it’s several comments before? And your first comment is right at the top, even though around a dozen people posted before you, is that right?

  • Damian Edwards

    When I posted my first comments there were none others displayed on the page. Not sure if that means I was first though.

  • http://www.brothercake.com/ brothercake

    Oh, what that means then is that I’m getting emails in the wrong order! That’s a relief – it means the comments are displaying correctly; notification emails are a far less significant issue! Thanks for the confirmation.

  • http://www.brothercake.com/ brothercake

    Anyway … mouse and keyboard navigation – so the lesson here is that the script really shoud cater for that situation. It should be able to deal with events wherever they come from, and not assume (as it does currently) that a menu which was opened with the keyboard will inevitably be closed with the keyboard too.

  • memco

    I tried to implement this just now as I was excited to have a pre-built solution that handled everything for me. Then I tried to style this–it’s horribly documented. Why is there so much in the “structure” that breaks the menu even though it seems unnecessary? Perhaps a more in depth explanation of the menu or just better comments in the source would be good.

    In the meantime, can anyone recommend a good unobtrusive JS menu that does offer keyboard navigation?

  • http://www.brothercake.com/ brothercake

    Why is there so much in the “structure” that breaks the menu even though it seems unnecessary?

    Because it is necssary.

    I’m sorry if this isn’t what you need. These demo were not really intended to be a ready-packaged solution that you can just take and make your own with 2 minutes customisation. If that’s what you want you’d be better off looking at a commercial solution, like this one.

    These demos are here to illustrate a set of general principles, but if you’re prepared to look on this as a learning exercise, well then — what problems are you having?

  • Josh Bowes

    Great post. I had to change the CSS position attribute from ‘absolute’ to ‘relative’ to work in my situation. I also found that in IE6 the menu did not work well if embedded in a table, although it may have been some funky js or CSS that was being executed and I was unaware of.

    Thanks again!

  • http://www.lunadesign.org awasson

    James,
    Nice menu!

    I joined the conversation much earlier but didn’t have time to have a good look at the menu until this weekend. I’ve spent a couple of hours reviewing/modifying it because there is a lot in it that I’m not all that familiar with and it is great! I really like the keyboard controls and the delay. Good article and a really great piece of code to play with!

    @memco: Use Firefox with the Firebug plugin to get a good idea of what part of the stylesheet controls the menu at various mouseover points. The stylesheet is really well structured for editing and after you get the hang of it, it shouldn’t need any commenting. You can add your own via your sleuthing with Firebug

  • greg

    I find my clients want the animation and look of flash menus. This would be great for alternative div content though.

  • Paul

    @CSU-Bill “I have seen and am currently working on using a pure CSS drop-down menu that does not flicker. If you want to see it, visit http://www.grc.com/menudemo.htm and you can also read the information about the menu. I am trying to add another level so that it matches my current menu.”

    Sorry dude, but your menu does not do what you said. Narrow windows do not see the right side menu slide out. If you want it to be handled in narrow viewing, I suggest you make the right side slide to the left not right.

  • http://www.intacinsaat.com celik proje

    nice simple menu, thanks for sharing.