Re: mouseenter, mouseleave, and touch compat/interop

A quick update: the tap event issue (missing mouseenter/mouseleave) has
been fixed, available in Chrome 43 (currently in dev channel). See
crbug.com/457497 for details. Note that my patch (crrev.com/1047733002)
also fixed two other bugs (crbug.com/470258, crbug.com/470947) with the
ordering of "pure" mouse-events.

Mustaq


On Fri, Mar 6, 2015 at 12:20 PM, Rick Byers <rbyers@google.com> wrote:

> Jacob,
> I realized it's not completely obvious what semantics we want here.
>  mouseenter/mouseleave are normally tied to matching :hover state exactly.
> In chromium we set :hover shortly after touchstart, and clear it on (or
> shortly after) touchend, which is very different from the WebKit-style
> synthetic mouse event behavior.
>
> So in this scenario, we have to choose one of the following:
>
> 1) Break the connection between :hover and mouseenter/mouseleave for tap
> gestures.  Fire the mouseenter/mouseleave events consistent with the
> existing mouse event sequence, i.e.:
> touchstart, touchend, mouseenter, mouseover, mousemove, mousedown,
> mouseup, click
> This is probably the most compatible thing, so probably what we want.  But
> it turns out it may be some non-trivial implementation work for us (since
> today our mouseenter/mouseleave logic is tied to setting/clearing of
> :hover).
>
> 2) Change our :hover behavior.  I know this is an area you and I have
> discussed as needing interoperability improvement.  Is now the time to talk
> about this in detail perhaps?
>
> 3) Break the mouse event sequence (but keep the mouseenter/leave :hover
> connection), so it might sometimes look something like this on
> dwell-then-drag gesture that normally doesn't fire any mouse events:
> touchstart, mouseenter, touchmove, mouseleave, touchend
> or like one of these (depending on timing) on a tap:
> touchstart, mouseenter, touchend, mouseover, mousemove, mousedown,
> mouseup, click, mouseleave
> touchstart, touchend, mouseenter, mouseover, mousemove, mousedown,
> mouseup, click, mouseleave
>
> I'd love to hear more about what exactly IE does when using WebKit-style
> mouse event behavior.  This seems even more complicated when you take
> pointer events in the mix (presumably the pointer->mouse event mapping gets
> disconnected).
>
> Thanks,
>   RIck
>
> On Tue, Feb 17, 2015 at 5:34 PM, Rick Byers <rbyers@google.com> wrote:
>
>> 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 Monday, 13 April 2015 14:40:59 UTC