Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Html5 (issue): canvas scrolling when interacting/dragging on iOS 11.3.

I have an HTML5 app that makes extensive use of its canvas. We started experiencing issues with touch after the iOS 11.3 update.

When implemented, we made sure to explicitly tell the user agent that the event should not be handled. (ie. we added evnt.preventDefault()

We also restricted the canvas, and make sure to disable the browser handling of all panning and zooming gestures. (touch-action: none, although not Safari does not officially support this basic implementation, this does work on any browser prior iOS 11.3)

This is NOT specific to any browser, but it manifests itself on any iOS device after the 11.3 device.

It can be reproduced using this JSFiddle: https://jsfiddle.net/w542djdw/15/

Any recommendation would be greatly appreciated.

like image 363
Carlos RT Avatar asked Aug 31 '25 21:08

Carlos RT


1 Answers

The trick is in how Safari 11.1 (bundled into iOS 11.3) deals with touch events.

From their release notes:

Web APIs:

  • Updated root document touch event listeners to use passive mode improving scrolling performance and reducing crashes.

So basically changing this:

// Prevent scrolling when touching the canvas
document.body.addEventListener("touchstart", function (e) {
    if (e.target == canvas) {
        e.preventDefault();
    }
}, false);
document.body.addEventListener("touchend", function (e) {
    if (e.target == canvas) {
        e.preventDefault();
    }
}, false);
document.body.addEventListener("touchmove", function (e) {
    if (e.target == canvas) {
        e.preventDefault();
    }
}, false);

Into this:

// Prevent scrolling when touching the canvas
document.body.addEventListener("touchstart", function (e) {
    if (e.target == canvas) {
        e.preventDefault();
    }
}, { passive: false });
document.body.addEventListener("touchend", function (e) {
    if (e.target == canvas) {
        e.preventDefault();
    }
}, { passive: false });
document.body.addEventListener("touchmove", function (e) {
    if (e.target == canvas) {
        e.preventDefault();
    }
}, { passive: false });

Reading Safari's (iOS 11.3) release notes makes sense after reading the documentation for EventTarget.addEventListener

passive: A Boolean which, if true, indicates that the function specified by listener will never call preventDefault(). If a passive listener does call preventDefault(), the user agent will do nothing other than generate a console warning. See Improving scrolling performance with passive listeners to learn more.

like image 181
Carlos RT Avatar answered Sep 03 '25 09:09

Carlos RT