Skip to main content

This Hover Cruft is Full of Ills

Recently I spent time refactoring much of the event system in jQuery for version 1.7. Since we added some new event methods as well, I took another pass at the event-related documentation. It was an opportunity to rewrite the pages in a way that make more sense (at least, to me) and eliminate things that were important five years ago but not so much today. Just like code, documentation accumulates its own cruft over time. I also find that when things get ugly or inconsistent in the code, they often get ugly or inconsistent in the documentation as well.

Here's an example: In jQuery 1.4.2 we started allowing people to use the "hover" event name for the .live() and .delegate() methods. This is the equivalent of attaching a "mouseenter" and "mouseleave" event to an element. Really. That is all it does. If you said $("button").bind("mouseover mouseleave", myFunc) you can now say $("button").bind("hover", myFunc) and save 16 taps on your keyboard. Many people seem to just love it, and I don't understand why.

jQuery's hover event is not a hover event at all. First of all, unlike any other event, when the actual events occur the event.type is "mouseenter" or "mouseleave", not "hover". Then there is the API confusion, since there is also a .hover() method that can accept two functions (separate functions for each event). Some people expect that somehow the .live() event binding method knows about the powers of this magic hover event and thus it will accept two functions as well. But no. Thank goodness.

Then there is the question of what .trigger("hover") would do. Somehow this peculiar behavior didn't infect triggering, so that will truly trigger a custom event named "hover" and have no effect on the mouseenter-mouseleave "hover" that was bound. Of course, you'll have a mighty hard time binding an event handler to your custom "hover" event anyway. I suppose that for consistency and symmetry it should trigger mouseenter and mouseleave events in quick succession. But that would be silly, right?

More bothersome still is the misappropriation of the term "hover" for both of those cases. When an airplane flies through the airspace directly over my house, it's not "hovering" there. When a helicopter flies to the vicinity of my house and hangs out in mid-air over the roof, now that's hovering. The word "hover" implies that the mouse at least slowed down for a while and spent time over the element. With the current implementation, you'll know only that the mouse happened to touch the element for a fleeting time. You'll see many naive dropdown-menu implementations that use bare mouseenter-mouseleave events and act way too jumpy. Either they drop down as your mouse pointer flies by, or they quickly close if your mouse strays the slightest bit off course.

Brian Cherne's jQuery hoverIntent plugin takes mouse velocity and timing into account and follows that intuitive idea of what hovering really means. If your mouse-tracking needs exceed a simple mouseenter-mouseleave situation, the odds are that you need that plugin. One day I'd love to remove the "hover" hack and the special-case code that goes with it.


Comments

Popular posts from this blog

Tragedy of the WebKit Commons

With Opera announcing that their future products will be based on WebKit, the Internet is abuzz with discussion about what that means and whether it's a good thing. Looking at it as a jQuery developer, it's a good thing if it gets WebKit participants to fix bugs and update older implementations. I can't be optimistic without some evidence that things are really going to change.

We don't know how many of Opera's core developers will move to WebKit development, but the press release isn't encouraging: "The shift to WebKit means more of our resources can be dedicated to developing new features and the user-friendly solutions." I suspect they want some cost savings by eliminating Presto technical staff, or -- in the most optimistic case for their employees -- refocusing existing staff on the parts outside WebKit core that make browsers different.

Opera did land their first WebKit patch so they wanted to make a statement that they weren't getting out o…

Please Stop the jsPerf.com Abuse!

According to many of the tests on jsperf.com, jQuery is slow. Really slow. The jQuery team gets bug reports from web citizens who've discovered these egregious flaws via jsperf and want them fixed. Now, jsperf.com can be a great tool when used knowledgeably, but its results can also be misinterpreted and abused. For example:

Why doesn't jQuery use DOM classList for methods like .addClass()?

There are at least three good reasons.
It doesn't make any practical performance difference given its frequency of use.It complicates code paths, since classList isn't supported everywhere.It makes jQuery bigger, which makes it load slower for everyone, every time.But this jsperf shows classList is much faster! How can you say that?

Well it's possible that test is running afoul of microbenchmark issues, and not measuring what it is supposed to measure due to the increased sophistication of today's JavaScript compilers. This is a big problem with a lot of the jsperf tests out …

You Might Not Need Babel

Babel is great, and by all means use it if it makes it easier to develop your application.

If you're developing a library on the other hand, please take a moment to consider whether you actually need Babel. Maybe you can write a few more lines of utility code and forego the need to pre-process. If you're only targeting some platforms, you may not need anything more than plain old ES6.

At the very least, make sure you know what Babel is doing for you, and what it's not. Some developers believe that Babel is protecting us from a great demon of code complexity when, in truth, browsers and node are pretty easy to deal with on their own. Let's take a look at some of the strategies for not needing Babel.

ES5 is pretty okay: In the days when we used tables for layout and the debugger was named alert(), we would have been so grateful if JavaScript had the features that ES5 has today. If you truly need Babel you are not only a weak programmer, but also an ingrate. Face it, you …