Skip to content

Instantly share code, notes, and snippets.

@amolk
Last active May 8, 2024 17:47
Show Gist options
  • Save amolk/1599412 to your computer and use it in GitHub Desktop.
Save amolk/1599412 to your computer and use it in GitHub Desktop.
Remove rubberband scrolling from web apps on mobile safari (iOS)
<!DOCTYPE html>
<html>
<head>
<title>Remove rubberband scrolling from web apps on mobile safari (iOS)</title>
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-touch-fullscreen" content="yes">
<meta id="extViewportMeta" name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
<script type="text/javascript" src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
<style>
html, body {margin: 0; padding: 0; overflow: hidden}
</style>
</head>
<body>
<script>
document.body.addEventListener('touchmove', function(event) {
event.preventDefault();
}, {
passive: false,
useCapture: false
});
window.onresize = function() {
$(document.body).width(window.innerWidth).height(window.innerHeight);
}
$(function() {
window.onresize();
});
</script>
Try pulling down this page with touch in iPhone/iPad, nothing happens! No rubberband scroll.
</body>
</html>
@icecodetim
Copy link

Removes bounce but can't scroll at all.

@matrixreal
Copy link

still scroll me too

@LeshM
Copy link

LeshM commented Dec 31, 2015

I tried lots of different approaches, but this was the thing that really worked:
https://github.com/lazd/iNoBounce

@lalasmuathasim
Copy link

Thanks for the code it worked well.

It gives a warning message in the console as "[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive". Any leads?

@mikebarnhardt
Copy link

@lalasmuathasim

Try switching to this:

  document.body.addEventListener('touchmove', function(event) {
    console.log(event.source);
    //if (event.source == document.body)
      event.preventDefault();
  }, {
    passive: false,
    useCapture: false
  });

Chrome auto-flags events as passive for touchmove and touchstart. Passive simply means you will never call event.preventDefault() in your handlers. It does this for performance reasons.

@yavuztas
Copy link

@amolk
Copy link
Author

amolk commented Oct 22, 2019

Updated GIST to include @mikebarnhardt's tweak above

@ImanMh
Copy link

ImanMh commented Jul 18, 2020

How about

body {
  position: fixed;
}

does that work too?

@fredlcore
Copy link

This is great and the first solution I found that really works on my iPhone. My problem is that I will have to run this on an ESP8266/ESP32 which won't have connection to the internet to download the jquery framework and flash space is too constrained to put it on there. I was wondering if you have an idea how to write this with "plain" JavaScript? Thanks a lot in advance!

@mikebarnhardt
Copy link

@fredlcore

Something like this might work.

  <script defer type="text/javascript">
    document.body.addEventListener('touchmove', function(event) {
      event.preventDefault();
    }, {
      passive: false,
      useCapture: false
    });

    function setWindowDimensions() {
      const styles = 'width: ' + window.innerWidth + 'px; height: ' + window.innerHeight + 'px';

      // or if using JS templates
      // const styles = `width: ${window.innerWidth}px; height: ${window.innerHeight}px`;

      document.querySelector('body').setAttribute('style', styles);
      
      // this might also work
      // document.body.style = styles;
    }

    // If you really need to check for DOM loaded before running this check out
    // this SO thread for solutions: https://stackoverflow.com/questions/4842590/how-to-run-a-function-when-the-page-is-loaded
    window.addEventListener('resize', setWindowDimensions);
  </script>

Obviously the defer attribute should prevent this code from running until the page load finishes, but I left a link in there if you really need to test for it or defer isn't supported.

@fredlcore
Copy link

fredlcore commented Sep 28, 2020

Thanks a lot, @mikebarnhardt - this works great in portrait mode at all times, and it also works in landscape mode, but until I press somewhere near the upper or lower end of the page so that the address bar appears. As long as the bar is visible, I can scroll the page. Once the bar has disappeared, the page is fixed again. This can result in a problem when the bar disappears when the page is scrolled partly out of the visible area. Then only the remainder of the page is visible.
In the original solution, this was not the case and the page was steadily fixed even when the address bar had appeared. Somehow there must be a difference between your solution and what the JQuery function does. Do you know what could be the difference?

@andre-fuchs
Copy link

How about

body {
  position: fixed;
}

does that work too?

Worked for me! Thanks.

@Ross-Hunter
Copy link

How about

body {
  position: fixed;
}

does that work too?

Worked for me! Thanks.

This works for me as well. Try this first as it's way way simpler than the alternatives.

@lotusorrose
Copy link

thank you!

@RyderCragie
Copy link

@mikebarnhardt, that stopped me from being able to scroll through the iframe, but now none of the page scrolls when you move your finger over the iframe.

I don't want the iframe to scroll, but I want the page to scroll.

@RyderCragie
Copy link

RyderCragie commented Mar 10, 2022

You can verify this on RyderCragie.com where the search bar and share button is.

@icyz
Copy link

icyz commented Jul 28, 2022

I tried lots of different approaches, but this was the thing that really worked: https://github.com/lazd/iNoBounce

this is the real working solution

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment