Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS Disable Page Scrolling with overflow-scrolling: touch

Let's say we want to make a webapp feel like a native app with "Add to Home Screen." One of the first steps is to disable the default scrolling. Easy, right?

// window or document
window.addEventListener("touchmove", function(event) {
    // no more scrolling
    event.preventDefault();
}, false);

That's all fine and dandy until you add overflow-scrolling to the mix. To be precise, on iOS it would be -webkit-overflow-scrolling: touch.

/* #scrollable happens to be a ul */
#scrollable {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}

By adding event prevention, hardware-accelerated scrolling in a container does not function, clearly not the intended effect.

The obvious solution looks something like this:

// you could do this for multiple elements, of course
var scrollable = document.querySelector("#scrollable");
scrollable.addEventListener("touchmove", function(event) {
    // no more bubbling :)
    event.stopPropagation();
}, false);

This solution introduces a problem, however, if you try to scroll left or right in #scrollable, it reverts back to the default scroll listener. Clearly, then, you should monitor the events to see if the touchmove event is tracking left or right, right? Unfortunately, no, as it will also, under circumstances I don't entirely understand, revert to the default scroll listener when scrolling vertically in the container.

Now what? To make matters worse, we would ideally be able to handle click or click-like events on the individual lis (read: touchstart):

var items = scrollable.querySelectorAll("#scrollable li");
for (var item = 0; item < items.length; item++) {
    items[item].addEventListener("touchstart", function() {
        // handle the touch start
    }, false);
}

To fix this problem, we could turn to simply using click events, but that defaults the goal of making the webapp "feel" native due to the delay between tapping and response. To solve this, we'll add an event listener for touchstart and touchend:

var items = scrollable.querySelectorAll("#scrollable li");
var activeItem = null, startTouch = null;
for (var item = 0; item < items.length; item++) {
    items[item].addEventListener("touchstart", function(event) {
        startTouch = event.touches[0];
        activeItem = this;
    }, false);
    items[item].addEventListener("touchend", function(event) {
        var touch = event.changedTouches[0];
        var deltaX = touch.pageX - startTouch.pageX
        var deltaY = touch.pageY - startTouch.pageY;
        // require the touchstart to be within 10 pixels of the touchend
        if (deltaX * deltaX + deltaY * deltaY <= 100)
            // handle "click" event
    }, false);
}

That's all fine and good, but we still haven't solved the problem with default page scrolling taking control of some touchmove events. Any ideas?

like image 930
skeggse Avatar asked Mar 09 '13 17:03

skeggse


People also ask

How do I disable scroll overflow?

To hide the scrollbar and disable scrolling, we can use the CSS overflow property. This property determines what to do with content that extends beyond the boundaries of its container. To prevent scrolling with this property, just apply the rule overflow: hidden to the body (for the entire page) or a container element.

How do I turn off scrolling In IOS?

The most straightforward way for disabling scrolling on websites is to add overflow: hidden on the <body> tag. Depending on the situation, this might do the job well enough.

How do I disable touch scroll?

Open the Settings app and go to the Devices group of settings. Go to the Touchpad tab. Scroll down to the Zoom and Scroll section, and uncheck the 'Drag two fingers to scroll' option.


1 Answers

Try swapping around the logic in your window and scrollable element listeners like so:

// window or document
window.addEventListener("touchmove", function(event) {
  if (!event.target.classList.contains('scrollable')) {
    // no more scrolling
    event.preventDefault();
  }
}, false);

// No special listeners needed on .scrollable elements

This way, you only prevent default when trying to scroll non-scrollable elements.

You will still have a problem that at the top/bottom of the scrollable content starting a drag can cause the whole app to "bounce". To fix this problem, see Joe Lambert's ScrollFix.

like image 177
rharper Avatar answered Oct 27 '22 06:10

rharper