This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 26809 - IE11 on Win8.1 fires a click event after pointer has moved when element has touch-event: none
Summary: IE11 on Win8.1 fires a click event after pointer has moved when element has t...
Status: RESOLVED WONTFIX
Alias: None
Product: PointerEventsWG
Classification: Unclassified
Component: Pointer Events specification (show other bugs)
Version: unspecified
Hardware: PC Windows NT
: P2 normal
Target Milestone: ---
Assignee: Jacob Rossi [MSFT]
QA Contact: Pointer Events Bugzilla list
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-09-15 13:59 UTC by saeid
Modified: 2014-09-24 13:02 UTC (History)
3 users (show)

See Also:


Attachments
IE11 console (168.03 KB, image/png)
2014-09-16 07:53 UTC, Patrick H. Lauke
Details

Description saeid 2014-09-15 13:59:24 UTC
When I touch an HTML element, move my finger during the touchdown and then lift it up while still over the same element, IE11 in Win8.1 touch fires a click event. This only happens if element or parent of it has "touch-event: none". A real life example would be a slideshow in which slides themselves are wrapped in anchor elements to allow them act as links, while at the same time allowing users to swipe the slides on touch devices without triggering the link functionality. Neither iOS nor Android fire a click event when touchend and touchstart happen at different coordinates, which makes me wonder if the behavior I'm experiencing in IE is wrong.

Here is a test page that shows this issue:
http://repos.saeidmohadjer.com/bxslider-4/test/test.html

Thanks
Saeid
Comment 1 Patrick H. Lauke 2014-09-15 15:39:57 UTC
Intuitively, this seems expected behavior to me based on the spec.

Normally (on iOS/Android) in the touch event model, if you move your touch point too much (there is a tiny bit of wiggle room, a few pixels at most, just to smooth out interaction for users that don't have super-steady fingers, particularly on high-dpi devices), the UA assumes that what you're actually doing is a some sort of scroll/movement/gesture. In this case, no compatibility events are fired, as these are really sent as fallback to convert "tap" gestures into mouse events to allow the current and legacy web to work on touchscreens. In the touch event model 'click' is considered to be a compatibility event (same as the simulated mouse events), and compatbility events are not fired unless it's a "clean" tap (without too much movement) - so it's true that iOS/Android do not fire 'click' in this scenario.

Pointer Events have some key differences. Most notably, click is NOT considered a mouse compatibility event - it can be fired regardless of whether or not mouse compat events (mouseover, mouseenter, mouseout, mouseleave, mousemove) are to be fired (for instance, if there are 2 or more pointers, they can all end up firing 'click' ... in touch events, only the first touch can generate mouse compat events, and - if i recall correctly - these are suppressed as soon as there's more than one touch anyway). But, more relevant to this particular case, when touch-action:none is set then the UA's default behavior is overridden. Normally, even with Pointer Events, if you move your touch point too much (again, there are a few pixels of wiggle room), it is again considered that you're really doing some gesture or scroll behavior - so the pointer is cancelled (pointercancel is fired) and it's left up to the UA to handle any further movement/interaction. This means that no more pointermoves, mouse compatibility events, or any final 'click' are being fired either. However, when touch-action:none is in effect, UA behaviors are suppressed, so the UA does NOT assume the extra movement was part of a scroll or similar - so any movement results in events being dispatched to your script, including mouse compat events along the way and a final 'click' when lifting the touch point.
Comment 2 Patrick H. Lauke 2014-09-15 20:01:07 UTC
A perhaps simpler way to conceptually understand this is:

- pointer events are based on mouse events (they extend them)
- with touch-action:none, you're suppressing any UA-specific behavior piled on top of a touch (as touching is overloaded on touchscreen devices...a touch is used both for activating things AND for scrolling etc)
- the end result is that with touch-action:none you get pretty much the equivalent behavior to mouse events (where you also see a 'click' happening if you did a mousedown on the element, moved the mouse around while the button is pressed, and then released the mouse again over the same element)
Comment 3 saeid 2014-09-16 07:15:35 UTC
(In reply to Patrick H. Lauke from comment #2)
> - the end result is that with touch-action:none you get pretty much the
> equivalent behavior to mouse events (where you also see a 'click' happening
> if you did a mousedown on the element, moved the mouse around while the
> button is pressed, and then released the mouse again over the same element)

This is certainly not true, unless you are on IE11/Win8. Just mousedown on yellow box in my test page, move the mouse around and then release it and you will see that no alert box pops up, i.e. no click is fired. This is the case in every browser that I now except IE11 on Windows 8.1 touch.

I just can't understand why dragging an element should trigger a click! Every touch-enabled slideshow that has linked slides or links inside slides will break because of this.

Also when I look at the sequence of pointer events in my test page (logged in console), I see that no pointercancel is being fired at all. IE fires a pointerup and then a click immediately after pointermove events. It just doesn't care whether pointerup is happening at pointerdown location or far away from it.
Comment 4 Patrick H. Lauke 2014-09-16 07:53:16 UTC
Created attachment 1515 [details]
IE11 console

event sequence of touching the yellow box, moving the finger around, and releasing the finger while still within the yellow box. pointerup > click.
Comment 5 Patrick H. Lauke 2014-09-16 08:10:13 UTC
> This is certainly not true, unless you are on IE11/Win8. Just mousedown on
> yellow box in my test page, move the mouse around and then release it and
> you will see that no alert box pops up, i.e. no click is fired. This is the
> case in every browser that I now except IE11 on Windows 8.1 touch.

Interesting, because I'm seeing this exact behavior in Chrome and Firefox on Windows. What may be masking the effect is that, as part of the normal browser behavior, when you click and drag on a link in browsers you generally trigger a "drag this link" behavior (to save a shortcut to your desktop, for instance).

To counter this, I've slightly modified your code, firing a preventDefault on mousedown. http://codepen.io/patrickhlauke/pen/FixgC - open this in Chrome or Firefox, click, drag and release while staying within the yellow box. 'click' is fired. And this is the behavior that you're seeing in IE11/Win8.1 with pointer events when touch-action:none.

> Also when I look at the sequence of pointer events in my test page (logged
> in console), I see that no pointercancel is being fired at all. IE fires a 
> pointerup and then a click immediately after pointermove events. It just 
> doesn't care whether pointerup is happening at pointerdown location or far 
> away from it.

Two things: it's not firing a pointercancel as the pointer is not canceled. As I said in my first response, *normally* you'd get a pointercancel because the UA is signalling "ok, this isn't just a click...must be a gesture like scroll...cancel the pointer, I got this". But when you have touch-action:none you're saying to the UA "disregard any standard behavior handling or gestures...my JavaScript will handle all interactions". So the pointer is *not* canceled, and all the relevant event are sent to your script. Again, this is expected behavior (and matches what happens with the mouse, as per the example above).

> I just can't understand why dragging an element should trigger a click!

Again, this is exactly what happens for mouse currently in all browsers (barring UA behavior like "drag the link", or similarly "drag an image", which need to be suppressed (and most old-school "mouse-draggable" slideshow scripts do this with preventDefault on mousedown or similar). 

> Every touch-enabled slideshow that has linked slides or links inside 
> slides will break because of this.

Any current touch-enabled slideshows will be coded to react to touchstart/touchmove/touchend, not pointer events, so breakage should not occur that often by virtue of them not actually working on IE11/Win8.1 on a touchscreen device at all. Any newly coded slideshows that do take pointer events into account will also need to take into account this behavior of pointer events (that a click is fired even after movement has occurred).

> It just doesn't care whether pointerup is happening at pointerdown
> location or far away from it.

Far away perhaps, but still within the boundaries of the original element where the pointerdown happened. And again, just as with mouse events.
Comment 6 Patrick H. Lauke 2014-09-16 08:25:38 UTC
For completeness: here's a short screencapture of my codepen in Chrome/Win8.1 https://www.youtube.com/watch?v=VUXiBguycaw - note how click is fired regardless of whether or not the mouse pointer is near or far from the point where the original mousedown happened, as long as it's still within the yellow box - which is the same behavior for pointer events with touch-action:none
Comment 7 saeid 2014-09-16 21:53:56 UTC
It seems we have different understanding of what a click is. My understanding of a click event is in line with W3C's definition below (pasted from Document Object Model Events spec):

"A click is defined as a mousedown and mouseup over the same screen location. The sequence of these events is:  mousedown, mouseup, click"

Note the requirement for mousedown and mouseup to be over the same screen location to trigger a click event. As far as I can say touch events implementations also respect this definition and trigger a click only when touchstart and touchend are over the same screen location. That's why it comes to me as a surprise that pointer events suddenly don't care about the same screen location requirement when triggering a click event.
Comment 8 Patrick H. Lauke 2014-09-16 23:18:21 UTC
> It seems we have different understanding of what a click is.

And so, apparently, do all browsers. Did you try that codepen example? Did you see the video showing the current behavior right there in Chrome (same happens in Firefox) when using a mouse?

> over the same screen location

Same screen location meaning "over the same element". It does not mean "on the exact same coordinates".
Comment 9 Patrick H. Lauke 2014-09-16 23:30:59 UTC
We could even simplify the codepen further, removing any preventDefault-ing that may appear like it's cheating...just a clean <div> and a click listener (changed the <a> to a <div> and left the <div> empty so browsers don't start doing some other default behavior, like dragging the link itself or highlighting text). http://codepen.io/patrickhlauke/pen/lBJhI

In Chrome or Firefox, with the mouse: press the mouse button down on the element, move the mouse while keeping button pressed, release mouse button somewhere else within the same element...click is consistently fired. And this is the behavior that effectively happens with Pointer Events, as this model extends mouse events. So this behavior is intended, and it's per spec.

Touch Events are fundamentally different from any other event handling that came before them...they did not inherit the traits of mouse events, so they behave differently. But it's not the case that Touch Events "respect" any kind of spec definition while Pointer Events don't.
Comment 10 saeid 2014-09-17 08:23:21 UTC
But the problem I'm facing involves a slider in which slide images are wrapped in anchor elements. Users should be able to swipe images on touch devices without triggering a click on wrapping anchor. This works on every desktop and touch browser except for IE10/11 on touch devices (Win 8.1 or Windows Phone mobiles) which use pointer events. Android and iOS do not trigger a click if a touchmove happens after a touchstart (that's why there is the famous 300ms delay on clicks), nor does Chrome on Windows 8.1 touch. You can see the problem if you try to swipe slides on this page:

http://repos.saeidmohadjer.com/bxslider-4/test/bxslider.html

How do you suggest to solve this problem with pointer events? In other words how can an anchor element be moved around without triggering a click on it? Click should only fire when user taps on the image, not when drags it.
Comment 11 Patrick H. Lauke 2014-09-17 10:28:12 UTC
> This works on every desktop and touch browser except for IE10/11 on touch 
> devices (Win 8.1 or Windows Phone mobiles) which use pointer events

I can only reiterate what I said all along: this is intended Pointer Events behavior, and it is exactly the same behavior you'd see if you tried to make your carousel slider work with the mouse. As such, it's not a bug with the spec, or with IE's implementation of the spec...it's by design.

> How do you suggest to solve this problem with pointer events? In other words 
> how can an anchor element be moved around without triggering a click on it?

As with trying to make it work with mouse, you'd need to implement your desired logic yourself with some basic state machine. Roughly:

- on pointerdown, keep a reference to the x/y coordinates and set a boolean flag to indicate we're now dealing with a "pressed" state. also set another boolean flag for "dragged" or whatever to false
- on pointermove, if "pressed" is true, check how far current x/y coordinates are from the original x/y coordinates where the pointerdown happened. if it's above a certain threshold (a few pixels, just to allow for some slightly unsteading touch/mouse interaction), set the "dragged" boolean to true
- on pointerup, reset "pressed" to false
- on click, check if "dragged" is true. if so, cancel the event (preventDefault, stopPropagation, etc). reset dragged to false

As an aside:

> Android and iOS do not trigger a click if a touchmove happens after a 
> touchstart (that's why there is the famous 300ms delay on clicks)

Not quite. the 300ms delay happens after touchend, and is there to wait and see if there's a second touchstart coming...i.e. to check if this touch was simply the first in a double/triple tap sequence, as the browser itself handles these. If after 300ms there was no follow-up touch, then the browser assumes it was a tap, and fires the mouse compat events and final click (provided there was not too much movement / there are no other touches on the screen, etc)
Comment 12 saeid 2014-09-23 08:58:37 UTC
Hi Patrick, 

I didn't get a chance to test your suggestions due to workload, but will do so this week. However, I should say that I'm surprised that you're saying in W3C's definition of a click, "over the same screen location" means "over the same element" and not what it literally says. I doubt if anyone would interpret it as that when reading: "A click is defined as a mousedown and mouseup over the same screen location."
Comment 13 Patrick H. Lauke 2014-09-23 09:01:18 UTC
> I doubt if anyone would interpret it as that

But, once more, that's exactly how Chrome and Firefox DO interpret it in the case of mouse events, as demonstrated.

https://www.youtube.com/watch?v=VUXiBguycaw


And because pointer events extend mouse events, that's where the behavior you're seeing comes from.
Comment 14 Patrick H. Lauke 2014-09-24 13:02:26 UTC
Closing this bug, as the behavior experienced matches the intention in the spec and is consistent with the behavior of mouse events, which Pointer Events extends http://www.w3.org/2014/09/23-pointerevents-minutes.html