Disable elastic scrolling in Safari

JavascriptJqueryCssSafariOsx Lion

Javascript Problem Overview


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!

Javascript Solutions


Solution 1 - Javascript

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.

Solution 2 - Javascript

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 https://stackoverflow.com/questions/7768269/ipad-safari-disable-scrolling-and-bounce-effect

Solution 3 - Javascript

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

Solution 4 - Javascript

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.

Solution 5 - Javascript

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

Solution 6 - Javascript

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
	}
);

Solution 7 - Javascript

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/

Solution 8 - Javascript

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;
			} 
		});

	}

Solution 9 - Javascript

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFabianView Question on Stackoverflow
Solution 1 - JavascriptAintaerView Answer on Stackoverflow
Solution 2 - JavascriptYiselaView Answer on Stackoverflow
Solution 3 - JavascriptsunderlsView Answer on Stackoverflow
Solution 4 - JavascriptMartinView Answer on Stackoverflow
Solution 5 - JavascriptLloekiView Answer on Stackoverflow
Solution 6 - JavascriptGavinView Answer on Stackoverflow
Solution 7 - JavascriptyckartView Answer on Stackoverflow
Solution 8 - JavascriptKieranView Answer on Stackoverflow
Solution 9 - JavascriptOwen DaveyView Answer on Stackoverflow