13

I am writing a web app in HTML and JavaScript for use on an iPhone. What I would like to achieve is preventing the app from elastic scrolling (scrolling past the pages extents and bouncing back). However, I need some of the longer elements of my app to be able to be scrolled (the app has a long canvas).

I have tried many answers to this found elsewhere on the internet, however, all of those solutions either used JQuery, disabled scrolling altogether, used Phonegap or just plain didn't work on IOS 7. How can I do this?

Phedg1
  • 1,888
  • 3
  • 18
  • 35
  • 1
    see this answer http://stackoverflow.com/a/16898264/112731 – Onur Yıldırım Jun 07 '14 at 01:19
  • 2
    possible duplicate of [How to disable rubber band in iOS web apps?](http://stackoverflow.com/questions/10357844/how-to-disable-rubber-band-in-ios-web-apps) – mplewis Jun 16 '14 at 02:28
  • 1
    The solution given on that question no longer works. You experience jittering at the upper and lower limits. – Phedg1 Jun 18 '14 at 04:18

4 Answers4

22

There is a way to achieve this without jQuery:

document.body.addEventListener('touchmove', function(event) {
    event.preventDefault();
});

But this is not a proper solution. It's better to wrap your content in some div, and use css property on it:

 -webkit-overflow-scrolling: touch;

Here is the example

Edit:

This will only prevent overscroll in webview, not in app. So you need to disable this feature in app config. If you use phonegap:

<preference name="DisallowOverscroll" value="true" />

More description here

If you don't use phonegap, you can use this.

Community
  • 1
  • 1
Umidbek
  • 1,504
  • 12
  • 26
1

The above solution was insufficient in my case. It prohibits all scrolling. It is possible to build a solution here that prevents elastic scrolling in iOS, but that still allows scrolling on children. I this took the above solution and added a check that bubbles up the DOM to determine which scrollable element "owns" the scroll event, and if it's the root element of the page, I drop it:

function overflowIsHidden(node) {
  var style = getComputedStyle(node);
  return style.overflow === 'hidden' || style.overflowX === 'hidden' || style.overflowY === 'hidden';
}

function findNearestScrollableParent(firstNode) {
  var node = firstNode;
  var scrollable = null;
  while(!scrollable && node) {
    if (node.scrollWidth > node.clientWidth || node.scrollHeight > node.clientHeight) {
      if (!overflowIsHidden(node)) {
        scrollable = node;
      }
    }
    node = node.parentNode;
  }
  return scrollable;
}

document.addEventListener('DOMContentLoaded', function() {

    document.body.addEventListener('touchmove', function(event) {
      var owner = findNearestScrollableParent(event.target);
      if (!owner || owner === document.documentElement || owner === document.body) {
        event.preventDefault();
      }
    });

}, false);

At this point, the body is no longer scrollable or elastically scrollable in iOS, but children elements are. You can then add -webkit-overflow-scrolling: touch; to those children so they are elastic but the document wont be. This will actually capture all scroll events even as you scroll to the bottom of the children, so the window's scroll position wont ever change erroneously. Alternatively you may also consider:

['resize', 'orientationchange', 'scroll'].forEach(function(event) {
  window.addEventListener(event, function() {
    window.scrollTo(0, 0);
  });
});

which in addition to the first code block I shared, should really throw an axe at document scrolling in ios altogether.

David Zorychta
  • 13,039
  • 6
  • 45
  • 81
1

So when you have scroll content in body & want to disable elastic scroll use:

let scrollToTop = $(window).scrollTop();
if (scrollToTop < 0) {
   // do something here
}

Because elastic scroll will always have negative value

shubh14896
  • 156
  • 1
  • 12
0

Based on answer by @umidbek this is how it worked for me

     document.getElementById('content-sections').
         addEventListener('touchmove', function (event) {
               event.preventDefault();
               return false;
         });
Pranay Dutta
  • 2,483
  • 2
  • 30
  • 42