Search code examples
javascriptandroidgoogle-chrometouchdom-events

What's a workaround for Chrome for Android's incorrect clientX and clientY behavior?


In Chrome for Android versions 16 and 18 (at least) there is a bug that reports clientX and clientY incorrectly. If the page is scrolled the values of clientX/Y will be incorrect for at least the touchstart event, though not the click event. There is a bug for it here:

https://code.google.com/p/chromium/issues/detail?id=117754

Which contains this example, that you can try yourself: http://www.apprisant.com/tab/cd.html

I have made a similar example with canvas here: http://codepen.io/simonsarris/full/dJcvn

These examples work on other mobile browsers (including the plain old Android Browser) but Chrome for Android seems to have broken clientX/Y on (at least some) touch events when scrolled.

Interestingly, clientX and clientY are not broken on the click event like they are on touchstart.

My question is, what's the best workaround to get clientX and clientY working consistently across browsers? It appears that offsetting with window.scrollX and window.scrollY will "solve" the issue, but a good workaround needs to:

  1. Determine that the browser is afflicted or not, preferably without making the user do anything and without resorting to checking the userAgent (so not making any assumptions of specific browser versions). In other words, how do we tell which browsers have bad values for clientX and clientY?
  2. Solve the issue reliably and only on those browsers where it needs solving (presumably, only Chrome for Android and only specific versions of it, as future versions may be fine), Seemingly, offsetting by window.scrollX/Y is the only thing that needs to be done here.

Solution

  • Simply use e.pageY - window.scrollY in place of e.clientY (or X, accordingly).

    e.pageY will give you where the event happened, and offsetting by window.scrollY will "remove the blank space" that is off-screen due to scroll. You COULD conditional check that e.pageY - window.scrollY === e.clientY, but since the workaround gives you the correct value, and you have to calculate it to check it anyways, that would be counter-intuitive.