Dropdowns revisited

For my DIBI presentation I need a dropdown menu (in order to compare it on desktop and mobile), so I wrote one.

Point is, it took me thirty lines of JavaScript, nine of which only contain a closing }, and three of which deal with the fact that bloody Firefox still doesn’t support contains().

Net amount of lines: 18. Can somebody please remind me why we all used to think dropdowns are so extremely complicated? I can’t for the life of me figure it out.

window.onload = function () {
	document.getElementById('dropdown').onmouseover = openMenu;
}

function openMenu(e) {
	var evt = e || window.event;
	var tgt = evt.target || evt.srcElement;
	while (tgt.nodeName !== 'LI') {
		if (tgt.nodeName === 'HTML') {
			return;
		}
		tgt = tgt.parentNode;
	}
	var nested = tgt.getElementsByTagName('ul')[0];
	if (nested) {
		nested.className = 'open';
		tgt.onmouseout = function (e) {
			var evt = e || window.event;
			var related = evt.relatedTarget || evt.toElement;
			if (!nested.contains(related)) {
				nested.className = '';
				tgt.onmouseout = null;
			}
		}
	}
}

/* Bloody Firefox STILL doesn't support contains */

if (window.Node && Node.prototype && !Node.prototype.contains) {
	Node.prototype.contains = function (arg) {
		return !!(this.compareDocumentPosition(arg) & 16)
	}
}

This is the blog of Peter-Paul Koch, web developer, consultant, and trainer. You can also follow him on Twitter or Mastodon.
Atom RSS

If you like this blog, why not donate a little bit of money to help me pay my bills?

Categories:

Comments

Comments are closed.

1 Posted by Paul Irish on 22 April 2010 | Permalink

Anyone know if there is a ticket tracking Node.prototype.contains on Mozilla's bugzilla?

Also, from your earlier post it seems we can assume support in all other desktop browsers?

2 Posted by kangax on 22 April 2010 | Permalink

"why we all used to think dropdowns are so extremely complicated?"

Because in this case:

1) you can get away with using DOM L0 event handlers

2) you don't make dropdowns accessible

3) you avoid handling className (if you had another class on submenu, mouseout handler would wipe it out)

4) you don't check existence of `compareDocumentPosition` before using it in `contains` shim (weak inference)

Taking care of all these things is not complicated, but the end result wouldn't be 18 loc.

Oh, and seriously, don't extend DOM. It's not at all hard to define `contains` as a separate function ;)

3 Posted by Luke Morton on 22 April 2010 | Permalink

Wouldn't this be more accessible and easier to do in CSS anyway? Then again what is the touch screen support like with CSS drop downs? (Time for some experimentation.)

@kangax what's with the wink lol?

Why am I asking questions? I'll answer that one.. coffee.

4 Posted by ppk on 22 April 2010 | Permalink

@kangax:

1) wouldn't increase the line count

3) wouldn't increase the line count; a simple className.replace would do the trick.

4) OK, would increase line count by 1.

As to accessibility: yes, there you're right, although I don't think we need a lot more lines to handle a few focus/blur events.

So make it 25 max.

Still, my point stands. This kind of inaccessible functionality used to be a Holy Grail. I can imagine that it'd be hard to create for Netscape 4, but it's been dead for eight years or so, and after its demise people still complained about dropdown menus.-

5 Posted by Brian LePore on 22 April 2010 | Permalink

This is 94 lines shorter than the one from your book. Nice improvement there. ;) Sure, that script offers more styling options than the above, but that only be like 2 lines of code to add in here I believe.

From your compatibility tests it seems like Opera Mini does support onmouseout, but you say minimally. I seem to be having difficulty doing it on my Droid. Am I just doing it wrong, or does Opera's support suck that much?

6 Posted by kangax on 22 April 2010 | Permalink

@ppk

In #1, I'm talking about using addEventListener/attachEvent instead of DOM0 (those would obviously increase the size).

Only I don't really see a reason to use them here, hence — "you can get away".

Speaking of accessibility, it's usually a good idea to also introduce slight delay in disappearance when hovering out, but I guess that's already a luxury.

7 Posted by AlastairC on 22 April 2010 | Permalink

The accessibility/usability angle is the main thing for me, they tend to be very fiddly compared to OS style drop-downs.

For example, with Windows/OSX drop-downs there is a time-out for when the thing should disappear if you mouse out, to make it easier.
(James Edward's http://www.udm4.com/ deals with this, plus a lot more, like cross-browser keyboard access.)

Then there was the pure-CSS drop-down fad, which gave people a new difficult thing to try!

8 Posted by Sasha Sklar on 22 April 2010 | Permalink

1. Why not use pure CSS drop downs for good browsers, with a patch for IE's lack of support for the :hover pseudo-class on non-anchor elements?

2. For IE you can use the proprietary mouseenter/mouseleave events for even simpler code.

9 Posted by minnie on 23 April 2010 | Permalink

@kangax, what's wrong about extending the DOM with a standard function that the browser doesn't implement? That's not a proprietary extension.

I second the CSS suggestion. You could use CSS animation (not widely supported, OK) to delay the fadeout.

Accessibility also means accounting for disabled Javascript, so the display:none should be set by an onload script.

10 Posted by palig on 23 April 2010 | Permalink

Guys, I think that you are missing the point.

This is not "The best drop-down menu ever" - so all that crappy (sorry) comments about what is missing, about usability etc... are totally wrong.

This is just a great example of how 'times goes by'!

11 Posted by kangax on 23 April 2010 | Permalink

@minnie

There are few things that suck about extending DOM. I wrote about it recently: http://perfectionkills.com/whats-wrong-with-extending-the-dom/

And how is `contains` not a proprietary extension? Which standard is it specified by?

12 Posted by Weixi Yen on 23 April 2010 | Permalink

Well to be fair, "times went by" when people realized they can do with with only CSS, but I get your point :)

13 Posted by Ionut Popa on 28 April 2010 | Permalink

What's wrong with pure css dropdowns and js for the poorer standards implementing browsers?

14 Posted by pablo on 29 April 2010 | Permalink

Hi,
Am i the only one who just see that as a pure glimpse of art ?

15 Posted by Delan Azabani on 7 May 2010 | Permalink

Nice, concise code, I like that! ;)

Recently, I wrote a right-click menu script that for once doesn't actually look like it's from 1999. Though it doesn't support submenus, I think it's sufficient for its purpose running at 94 lines.

(Also, none of that CSS-inside-JS crap.)

The script can be found here: http://azabani.com/js/quickmenu

...along with its blog post, which doubles as a live example: http://azabani.com/19

16 Posted by efraim on 8 May 2010 | Permalink

@palig:

No I don't think everyone but yourself are missing the point. The ppk's articles are usually interesting and well researched but this one just smells like the true and tried "that windows 3.1 uses so much more memory than my DOS 4.0; Oh and takes ton of disk space"
Yes it does but they have different feature sets.

If you leave out the difficult to get right in cross browser manner stuff, like keyboard navigation, nested menus, fade outs and delays for usability then it is short and easy - but so is painting icon for your application as opposed to drawing a painting.