Prevent Scroll Bounce for the Body Element, But Keep It for Child Elements in iOS

Prevent scroll bounce for the body element, but keep it for child elements in iOS

OLD INFO: I've solved this: http://www.hakoniemi.net/labs/scrollingOffset/nonbounce.html

NEW INFO: This is now a jQuery plugin that can be found from here: http://www.hakoniemi.net/labs/nonbounce/.

There are several issues, like losing the zooming capability when this is applied or it's dynamic updating isn't working fluently.

But now the simplest way is to define: <div class="nonbounce">...</div> and then $.nonbounce();

iPhone Web App - Stop body scrolling

After reviewing several solutions, I began to create a custom solution:

bouncefix.js

http://jaridmargolin.github.io/bouncefix.js/

Usage:

bouncefix.add(el)

Apply fix so that the given element no longer causes a full body elastic bounce when scrolling at its extremes.

bouncefix.remove(el)

Remove all listeners/observers responsible for fixing the full body elastic bounce.

Why?

Scrollfix was a good start, however I noticed several problems:

  1. It only worked when there was scrollable content. If you had an
    empty page, the bounce effect on the body would occur.
  2. The API did not expose a method to remove the listeners. My app will
    have multiple pages, and it didn't feel right to keep all of the
    listeners attached as the user moved around the app.

How?

It uses a similar approach to that of scrollfix. The problem occurs when you are at one of the scrolling extremes. On touchstart, we look to see if we are at the top extreme or bottom extreme, adding 1px if we are at the top, and removing 1px if we are at the bottom.

Unfortunately, this trick only works if we are able to set the scrollTop value. If the content is not yet scrollable, for example, you only have 1 list item, the whole body will again scroll. Bouncefix.js will take care of all of this behind the scenes by using event delegation and checking the scrollHeight against the offsetHeight anytime touchstart is triggered. In the case that there is no scrollable content, all scrolling on the container is blocked with e.preventDefault();

Disabling iOS elastic body scroll & keep native scrolling working

I've adapted the good solution from Conditionally block scrolling/touchmove event in mobile safari using Dojo:

var initialY = null;
dojo.connect(document, 'ontouchstart', function(e) {
initialY = e.pageY;
});
dojo.connect(document, 'ontouchend', function(e) {
initialY = null;
});
dojo.connect(document, 'ontouchcancel', function(e) {
initialY = null;
});
dojo.connect(document, 'ontouchmove', function(e) {
if(initialY !== null) {
if(!dojo.query(e.target).closest('#content')[0]) {
// The element to be scrolled is not the content node
e.preventDefault();
return;
}

var direction = e.pageY - initialY;
var contentNode = dojo.byId('content');

if(direction > 0 && contentNode.scrollTop <= 0) {
// The user is scrolling up, and the element is already scrolled to top
e.preventDefault();
} else if(direction < 0 && contentNode.scrollTop >= contentNode.scrollHeight - contentNode.clientHeight) {
// The user is scrolling down, and the element is already scrolled to bottom
e.preventDefault();
}
}
});

The element to be scrolled is #content in this case.

iOS - css/js - Overlay scroll but prevent body scroll

There is no way around this right now. As of iOS 9.3 there's still no good way to prevent the scroll on the body. The best method that I currently implement on all sites that require it is to lock the html and the body's height and overflow.

html, body {
height: 100%;
overflow: hidden;
}

This is the best way to prevent iOS scroll on the content behind the overlay/modal.

Then to preserve the scroll position I shift the content behind up to look like its retaining it then when the modal closes restore the body's position.

I do this with a lock and unlock function in jQuery

var $docEl = $('html, body'),
$wrap = $('.content'),
$.scrollTop;

$.lockBody = function() {
if(window.pageYOffset) {
scrollTop = window.pageYOffset;

$wrap.css({
top: - (scrollTop)
});
}

$docEl.css({
height: "100%",
overflow: "hidden"
});
}

$.unlockBody = function() {
$docEl.css({
height: "",
overflow: ""
});

$wrap.css({
top: ''
});

window.scrollTo(0, scrollTop);
window.setTimeout(function () {
scrollTop = null;
}, 0);
}

When you piece all these together you get http://codepen.io/jerrylow/pen/yJeyoG if you want to test it on your phone here's just the result: http://jerrylow.com/demo/ios-body-lock/

Prevent iOS bounce without disabling scroll ability

This code should stop the bounce as it's the HTML tag that bounces

html {
height : 100%;
overflow: hidden;
position: relative;
}
body {
height : 100%;
overflow: auto;
position: relative;
}

Prevent overflow / rubberband scrolling on iOS

The solution:

Type 1:

The most basic solution to prevent overflow scrolling on the element itself is to prevent default on touch events.

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

This method however disables the browsers native momentum scroll and is thereby not suitable for most applications. With some refinement however (only prevent if at top scrolling up or at bottom scrolling down, ...) this method fixes most problems. Many possible implementations can be found in this SO post.

Type 2:

Overflow scrolling on the body however is not prevented by methods described above.

One possible solution which seems reasonable is to prevent the element from ever being at its top or bottom position as described as best solution on mentioned question.

anElement.addEventListener('touchstart', function( event ){
if( this.scrollTop === 0 ) {
this.scrollTop += 1;
} else if( this.scrollTop + this.offsetHeight >= this.scrollHeight ) {
this.scrollTop -= 1;
}
}

This however did not reliably work on iOS 9.3.2.

What did work however is setting position: fixed on the <body> element to prevent the body from moving. Please note however that this still does not completely stop type 2 from happening, which is why sometimes you cannot scroll/focus any element because in the background type2 with its focus lock is still happening (again, after you stop touching the screen for a moment it again works as expected).

While this is still far from being the optimal solution it seems to be the best we can get for the time speaking.

Edit: Please note that I am not sure if it is safe to put position: fixed on a <body> element. To track possible issues I have created following SO post. Apparently it might be better to create a wrapper element as child of body and set that element to position: fixed to avoid zoom problemes.


Edit 2: The definite solution

The script iNoBounce works wonders. Just load it to the page and experience a bounce-free web application. So far I have not found any problems with this solution.

iOS 10 Safari: Prevent scrolling behind a fixed overlay and maintain scroll position

Add -webkit-overflow-scrolling: touch; to the #overlay element.

Then add this JavaScript code at the end of the body tag:

(function () {
var _overlay = document.getElementById('overlay');
var _clientY = null; // remember Y position on touch start

_overlay.addEventListener('touchstart', function (event) {
if (event.targetTouches.length === 1) {
// detect single touch
_clientY = event.targetTouches[0].clientY;
}
}, false);

_overlay.addEventListener('touchmove', function (event) {
if (event.targetTouches.length === 1) {
// detect single touch
disableRubberBand(event);
}
}, false);

function disableRubberBand(event) {
var clientY = event.targetTouches[0].clientY - _clientY;

if (_overlay.scrollTop === 0 && clientY > 0) {
// element is at the top of its scroll
event.preventDefault();
}

if (isOverlayTotallyScrolled() && clientY < 0) {
//element is at the top of its scroll
event.preventDefault();
}
}

function isOverlayTotallyScrolled() {
// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions
return _overlay.scrollHeight - _overlay.scrollTop <= _overlay.clientHeight;
}
}())

Remove 'bouncy scrolling' on mobile devices

It sounds like what you're looking for is to disable the scroll bounce for a UIWebView in iOS. If you're developing a native iOS app, you can disable the bounce by setting [WebViewObject].bounces = NO where [WebViewObject] is the UIWebView.

If you're just looking to prevent the bounce in the Safari mobile browser, I don't believe there's a way to do this.



Related Topics



Leave a reply



Submit