61

I just wanted to diable the elastic scrolling/bounce effect in Safari (OSX Lion).

I found the solution to set overflow: hidden for body in css, but as expected it only disables the scrollbar, so if the website is "longer" than the screen you won't be able to scroll!

Any solutions or hints are welcome! Thanks!

Fabian
  • 3,465
  • 4
  • 34
  • 42
  • I’m curious what need there might be for this. Let the system do its thang, is usually my motto. – Alan H. Nov 07 '12 at 23:55
  • 11
    It's for single page apps, which are designed to look more like desktop apps I think. – william44isme Dec 10 '13 at 21:09
  • 4
    It's a design decision made without our consent that simply doesn't suit all possible web apps. – Dom Vinyard Jun 26 '15 at 22:10
  • Just make a container within body for all of your content and keep the `overflow:hidden;`? – www139 Nov 27 '15 at 17:02
  • Elastic scroll severely interferes with the performance of setTimeout (in Chrome, at least) - if you're doing WebAudio scheduling on-the-fly disabling elastic scroll can reduce the risk of drop-outs. – stephband Sep 12 '16 at 09:36
  • Actually, strike that. Even if you disable elastic scrolling setTimeout still misbehaves when scrolling beyond the limit of the page (even if the page content does not move). – stephband Sep 12 '16 at 09:43

9 Answers9

75

You can achieve this more universally by applying the following CSS:

html,
body {
  height: 100%;
  width: 100%;
  overflow: auto;
}

This allows your content, whatever it is, to become scrollable within body, but be aware that the scrolling context where scroll event is fired is now document.body, not window.

Gajus
  • 69,002
  • 70
  • 275
  • 438
Aintaer
  • 2,131
  • 17
  • 15
  • 3
    This works not just on Safari, but on Chrome, and probably Firefox as well. Thanks! – kolinko Oct 05 '13 at 09:46
  • 21
    Since applying this CSS will remove momentum scrolling on iOS, don't forget to add **-webkit-overflow-scrolling: touch** to the **body** to re-enable momentum scrolling on iOS. – Bobby Nov 06 '13 at 04:43
  • Works great for disabling bounce, but I'm not able to capture the scroll event on document.body, as such `$(document.body).on("scroll", function() { console.log('scrolling') });` I also can't capture on the scrolling element itself. Any ideas? – jordancooperman Jan 27 '14 at 18:34
  • 1
    Hmm, have you tried inspecting which element is actually scrolling? It sounds like another element on the page is scrolling instead of the page body. – Aintaer Feb 07 '14 at 17:09
  • This solved the issue, though I think it's worth noting that I had to change all of my `scroll` event listeners to listen to `document.body` instead of `'window'`. – Walter Roman Mar 20 '14 at 20:28
  • 6
    Resurrecting this... This doesn't seem to work on ios 7 (chrome or safari). The body does scroll as expected, but once on an edge html scrolling seem to take over. – Yaron Apr 21 '14 at 16:17
  • Hmm, I haven't tried this in newest iOS yet. Platform level changes are difficult to override. – Aintaer Apr 23 '14 at 16:17
  • 4
    -webkit-overflow-scrolling: touch; seems to re enable the elastic scrolling. On another note, document.body.scrollTop, window.pageYOffset and window.scrollY don't give the value for how far the page has scrolled anymore after using this solution, they stay at 0. How can I find this? – Phedg1 Jun 13 '14 at 08:30
  • Please see @Yisela for why this is a bad hack! – jahrichie Aug 19 '14 at 17:12
  • On iOS 8 Safari, setting this CSS will restrict user entering the minimal-ui. – Gajus Nov 11 '14 at 17:30
  • Adding this CSS makes the fonts look all fuzzy on Chrome... weird. – François Zaninotto Nov 30 '15 at 23:31
  • 13
    This does not work at all for me. – Corey Jan 14 '16 at 20:22
  • 1
    Is this solution still supposedly correct? I cannot get it to work on an iPhone 6S with iOS 9.3. @Aintaer, if it does still work for you, can you provide a test page? – Michael Jun 09 '16 at 17:16
  • This can not work on ios 10 – angry kiwi Feb 05 '17 at 18:07
  • 4
    best solution https://www.bram.us/2016/05/02/prevent-overscroll-bounce-in-ios-mobilesafari-pure-css/ – angry kiwi Feb 05 '17 at 18:08
  • This made scrolling on mobile dreadfully slow in my scenario. When you combine all of them including @Bobby suggestion to be html, body { height: 100%; width: 100%; overflow: auto; -webkit-overflow-scrolling: touch; } It should work on iOS – Jared Eddy Sep 20 '19 at 22:36
15

If you use the overflow:hidden hack on the <body> element, to get back normal scrolling behavior, you can position a <div> absolutely inside of the element to get scrolling back with overflow:auto. I think this is the best option, and it's quite easy to implement using only css!

Or, you can try with jQuery:

$(document).bind(
'touchmove',
function(e) {
e.preventDefault();
}
);

Same in javasrcipt:

document.addEventListener(
'touchmove',
function(e) {
e.preventDefault();
},
false
);

Last option, check ipad safari: disable scrolling, and bounce effect?

Community
  • 1
  • 1
Yisela
  • 6,909
  • 5
  • 28
  • 51
  • 1
    Thanks, the css workaround works! I hoped that there may be a javascript/jquery solution, because this one isn't working for me. I think this will only work for iOS devices. Correct me if I'm wrong. – Fabian Nov 16 '11 at 12:17
  • 4
    The answer is a little convoluted. To target OS X, all you need is overflow: hidden on the html and body element. There is no "touchmove" event for OS X, which is the OS that is being asked about. – Matthew Dec 19 '11 at 23:42
  • If you're transitioning from jQuery, don't forget `document.querySelector('div');` `document.querySelectorAll('.someClass');` `document.querySelector('#someID');` – neaumusic Jun 16 '15 at 20:17
12

overflow:hidden;-webkit-overflow-scrolling:touch won't work well on iOS safari 8.1, as the fixed header will be out of visible area.

gif

As @Yisela says, the css should be placed on .container(the <div> below <body>). which seems no problem(at leas on safari iOS 8.1)

gif

I've place the demo on my blog: http://tech.colla.me/en/show/disable_elastic_scroll_on_iOS_safari

Community
  • 1
  • 1
sunderls
  • 760
  • 7
  • 8
12

I had solved it on iPad. Try, if it works also on OSX.

body, html { position: fixed; }

Works only if you have content smaller then screen or you are using some layout framework (Angular Material in my case).

In Angular Material it is great, that you will disable over-scroll effect of whole page, but inner sections <md-content> can be still scrollable.

Martin
  • 696
  • 6
  • 7
5

I made an extension to disable it on all sites. In doing so I used three techniques: pure CSS, pure JS and hybrid.

The CSS version is similar to the above solutions. The JS one goes a bit like this:

var scroll = function(e) {
    // compute state
    if (stopScrollX || stopScrollY) {
        e.preventDefault();              // this one is the key
        e.stopPropagation();
        window.scroll(scrollToX, scrollToY);
    }
}

document.addEventListener('mousewheel', scroll, false);

The CSS one works when one is using position: fixed elements and let the browser do the scrolling. The JS one is needed when some other JS depends on window (e.g events), which would get blocked by the previous CSS (since it makes the body scroll instead of the window), and works by stopping event propagation at the edges, but needs to synthesize the scrolling of the non-edge component; the downside is that it prevents some types of scrolling to happen (those do work with the CSS one). The hybrid one tries to take a mixed approach by selectively disabling directional overflow (CSS) when scrolling reaches an edge (JS), and in theory could work in both cases, but doesn't quite currently as it has some leeway at the limit.

So depending on the implementations of one's website, one needs to either take one approach or the other.

See here if one wants more details: https://github.com/lloeki/unelastic

Lloeki
  • 6,573
  • 2
  • 33
  • 32
4

None of the 'overflow' solutions worked for me. I'm coding a parallax effect with JavaScript using jQuery. In Chrome and Safari on OSX the elastic/rubber-band effect was messing up my scroll numbers, since it actually scrolls past the document's height and updates the window variables with out-of-boundary numbers. What I had to do was check if the scrolled amount was larger than the actual document's height, like so:

$(window).scroll(
    function() {
        if ($(window).scrollTop() + $(window).height() > $(document).height()) return;
        updateScroll(); // my own function to do my parallaxing stuff
    }
);
Gavin
  • 7,544
  • 4
  • 52
  • 72
3

You could check if the scroll-offsets are in the bounds. If they go beyond, set them back.

var scrollX = 0;
var scrollY = 0;
var scrollMinX = 0;
var scrollMinY = 0;
var scrollMaxX = document.body.scrollWidth - window.innerWidth;
var scrollMaxY = document.body.scrollHeight - window.innerHeight;

// make sure that we work with the correct dimensions
window.addEventListener('resize', function () {
  scrollMaxX = document.body.scrollWidth - window.innerWidth;
  scrollMaxY = document.body.scrollHeight - window.innerHeight;
}, false);

// where the magic happens
window.addEventListener('scroll', function () {
  scrollX = window.scrollX;
  scrollY = window.scrollY;

  if (scrollX <= scrollMinX) scrollTo(scrollMinX, window.scrollY);
  if (scrollX >= scrollMaxX) scrollTo(scrollMaxX, window.scrollY);

  if (scrollY <= scrollMinY) scrollTo(window.scrollX, scrollMinY);
  if (scrollY >= scrollMaxY) scrollTo(window.scrollX, scrollMaxY);
}, false);

http://jsfiddle.net/yckart/3YnUM/

yckart
  • 32,460
  • 9
  • 122
  • 129
  • This causes heavy flicker on our ipad, while preventing the page to scroll up/down. – tomazahlin Nov 24 '14 at 13:54
  • 2
    @tomazahlin ...and this is a reason for a *downvote*? Really?! – yckart Nov 25 '14 at 12:51
  • Sorry, but the solution itself is not good. It should only be applied to desktop computers. Mobile devices which are quite popular nowadays, have a problem with a method like this. So, I suggest if you can add some sort of check around the code, I guess it would be okay. – tomazahlin Nov 25 '14 at 16:36
  • 2
    @tomazahlin Sorry, but... The most things here, are just there to explain how something **could** work. All of the most code-examples are not ready-to-use, you have to dive into the code and take the part/s that interests you. If something doesn't fit your needs, dive deeper and fix it (...and maybe, open source it?!) – yckart Nov 25 '14 at 18:54
1

There are a to of situations where the above CSS solutions do not work. For instance a transparent fixed header and a sticky footer on the same page. To prevent the top bounce in safari messing things and causing flashes on full screen sliders, you can use this.

    if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {

        $window.bind('mousewheel', function(e) {

            if (e.originalEvent.wheelDelta / 120 > 0) {

                if ($window.scrollTop() < 2) return false;
            } 
        });

    }
Kieran
  • 71
  • 6
1

None of the above solutions worked for me, however instead I wrapped my content in a div (#outer-wrap) and then used the following CSS:

body {
   overflow: hidden;
}
#outer-wrap {
    -webkit-overflow-scrolling: touch;
     height: 100vh;
     overflow: auto;
}

Obviously only works in browsers that support viewport widths/heights of course.

Owen Davey
  • 1,202
  • 1
  • 12
  • 18