Re: mouseenter, mouseleave, and touch compat/interop

For the record, we agreed
<http://www.w3.org/2015/02/17-touchevents-minutes.html> that we should try
to fix the bug <https://code.google.com/p/chromium/issues/detail?id=457497>
with mouseenter/mouseleave not being fired in Chrome (Jacob says it looks
like it shouldn't be that risky).  Mustaq is aiming to land a fix in Chrome
43 and will follow up here once it's available in Canary for website compat
testing.

Rick

On Tue, Feb 10, 2015 at 8:05 PM, Rick Byers <rbyers@google.com> wrote:

> On Thu, Feb 5, 2015 at 10:36 AM, Jacob Rossi <Jacob.Rossi@microsoft.com>
> wrote:
>
>>  I’ve mentioned before that we’re exploring firing the Touch Event
>> spec’s model for compatibility mouse events so we’re more interoperable.
>> In doing so, we uncovered a nasty interoperability issue that’s quite
>> frustrating.  This one takes a minute to explain, so grab a cup of coffee
>> and bear with me. :-)
>>
>>
>>
>> Safari implements a proprietary heuristic for detecting hover menus.   It
>> works something like this on a simple tap:
>>
>>
>>
>> 1.       Fire touch events
>>
>> 2.       Fire mouse events for hover (e.g. mouseover/enter) , down, up
>>
>> 3.       If “page content changes” (insert undocumented proprietary
>> heuristic), then persist the hover on the node & suppress firing the click
>> event    [1]
>>
>> 4.       If not, then fire events to remove hover and fire click
>>
>>
>>
>> The heuristic is attempting to detect a hover menu intended for mouse,
>> which enables a “tap to hover menu, tap again to click” type of experience
>> when it works.  However, sometimes the heuristic has a false positive
>> causing non-hover-menus to require multiple taps to get a click event on
>> something.  This leads web developers to try to work around the heuristic.
>>
>>
>>
>> Here’s a common pattern we’ve found on popular sites like Netflix:
>>
>>
>> http://stackoverflow.com/questions/3038898/ipad-iphone-hover-problem-causes-the-user-to-double-click-a-link/22444819#22444819
>>
>>
>>
>> In summary, it looks like:
>>                 mouseenter – open hover menu
>>                 mouseleave – close hover menu
>>
>>                 click – toggle hover menu
>>
>>
>>
>> For a mouse in Safari, the menu opens when you mouse over and closes when
>> you click something or move your mouse out. Cool.
>>
>> For touch, the menu opens after you tap. The mouseenter causes “page
>> content changes” in step #2 above. Thus mouseleave and click do not fire.
>> Therefore the menu stays open.  You can tap again to click an item in the
>> menu. Cool.
>>
>>
>>
>> Now, consider a browser that does not implement Safari’s non-standard
>> heuristic.  In this case, Blink/Gecko follow the Touch Events spec [2]
>> essentially and do this:
>>
>> 1.       Fire touch events
>>
>> 2.       Fire mousemove
>>
>> a.       (While not explicitly mentioned in the spec, this causes a
>> mouseover to fire)
>>
>> 3.       Fire mouse down, up
>>
>> 4.       Fire click
>>
>>
>>
>> Note, like Safari, this means hover state essentially persists on the
>> node until you tap another node (which fires a new mousemove, which removes
>> hover from the old node and applies it to the new). The Touch Events spec
>> does not, however, explicitly state when hover related events, like
>> over/out/enter/leave occur. It’s just assumed the mousemove causes it
>> (grrr…the spec should say this!).
>>
>
> Agreed, please submit a PR for this.  I've always taken it for granted
> that over/out/enter/leave events should ALWAYS be consistent with mousemove
> (any time you get a move with a new target, they're fired appropriate), but
> stating that explicitly doesn't hurt.
>
> Still with me? :-) Here’s the rub:  Blink doesn’t fire
>> mouseenter/mouseleave for touch, only mouseover/mouseout (I didn’t have a
>> Firefox mobile device handy to test, but I assume it’s similar).  This is
>> despite the fact that Blink does support mouseenter/mouseleave for mouse
>> input. [3]
>>
>
> This is simply a bug from when mouseenter/mouseleave events were first
> implemented.  I only noticed this recently from code inspection (I added a FIXME
> in the code
> <https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/core/page/EventHandler.cpp&q=EventHandler.cpp%20mouseenter&sq=package:chromium&type=cs&l=2659>
> but failed to file a bug - just filed one now <http://crbug.com/457497>).
>
>
>>  It turns out this is a critical detail missing from the spec.  Because
>> if you make the mistake we did, which was to fire mouseenter/mouseleave
>> when processing the mousemove for touch, then the above code I described
>> breaks as you get:
>>
>>
>>
>> 1.       Fire touch events
>>
>> 2.       Fire mousemove
>>
>> a.       Fire mouseover
>>
>> b.      Fire mouseenter – open hover menu
>>
>> 3.       Fire mouse down, up
>>
>> 4.       Fire click – hover menu toggles
>>
>>
>>
>> So the hover menu opens and then immediately closes.  Not cool.
>>
>>
>>
>> tl;dr – for best compatibility, browsers need to choose either:
>>                 (a) try to reverse engineer Safari’s heuristic  (not
>> likely to be very interoperable)
>>
>>                 (b) do not implement mouseenter/mouseleave for touch
>>
>
> Crap crap crap crap.
>
> How prevalent is this pattern?  I.e. how much pain would we cause by
> fixing our bug in blink?
>
> The only pragmatic solution I can see (should we end up shipping the Touch
>> Event model for mouse events in IE) is B.  It should be noted that I’ve
>> tried to get the Safari engineers to share details about the heuristic, but
>> they have declined.
>>
>>
>>
>> I think this critical detail (not firing mouseenter/mouseleave for touch)
>> should probably be added as errata to the current spec. WDYT?
>>
>
> If we think this is what's best for the web (i.e. enough people have
> already taken a dependency on our bug), then that's OK with me (although as
> Patrick says - perhaps that's part of TEv2, not TEv1 errata).  It's not
> very rational though.  Is there a better pattern we could advocate for?
> What about combining this with some sort of more explicit signal of
> developer intent (like your aria-hasrole=popup)?  Ideally we'd have a path
> where browser's default behavior can be one (confusing) way for compat, but
> we have clear explicit APIs that could be implemented by all browsers to
> get developers out of this mess.
>
>  -Jacob
>>
>>
>>
>> [1]
>> https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html
>>
>> [2] http://www.w3.org/TR/touch-events/#mouse-events
>>
>> [3] https://status.modern.ie/dom3mouseentermouseleaveevents
>>
>>
>>
>>
>>
>>
>>
>
>

Received on Tuesday, 17 February 2015 22:34:55 UTC