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.
ipad safari: disable scrolling, and bounce effect?
This answer is no longer applicable, unless you are developing for a very old iOS device... Please see other solutions
2011 answer: For a web/html app running inside iOS Safari you want something like
document.ontouchmove = function(event){
event.preventDefault();
}
For iOS 5 you may want to take the following into account: document.ontouchmove and scrolling on iOS 5
Update September 2014:
A more thorough approach can be found here: https://github.com/luster-io/prevent-overscroll. For that and a whole lot of useful webapp advice, see http://www.luster.io/blog/9-29-14-mobile-web-checklist.html
Update March 2016: That last link is no longer active - see https://web.archive.org/web/20151103001838/http://www.luster.io/blog/9-29-14-mobile-web-checklist.html for the archived version instead. Thanks @falsarella for pointing that out.
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:
- It only worked when there was scrollable content. If you had an
empty page, the bounce effect on the body would occur. - 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();
Prevent Body Element From Scrolling On Touch Devices
I figured this out a few days ago and have this handy jsbin set up to demonstrate what I did to make this work:
My Working jsbin Example
When you open this link on an iPad, the text should be scrollable. Try tugging around the rest of the screen when there is no current touchmove event currently working.
If you play around with it, you'll notice that only the inner textfield moves as expected. This is determined by putting my .scrollable
class within the .container
class. The .scrollable
class takes up the full height of it's parent container.
Now make the container a larger height, like height: 500px
. The goal here is to make it large enough to have no overflow yet small enough to have other whitespace on the iPad still. Try scrolling it or pulling it... No touchmove events are fired and the screen stays in place.
My JS determines if an object has overflow after being touched. If it does, it scrolls. If it does not, it does not send a scroll event.
Play with it and let me know if I can provide any better examples and also if you run into any bugs... Right now the only one I know of is if you're really trying to break it and start tugging around the site while a current touchmove event is being fired, or the page is first loading... I wouldn't count those as "bugs", but if you can find a fix for those too, I'm all ears!
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();
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.
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;
}
Related Topics
Dropdown Image Not Visible in Chrome and Ie
Browser Support for Angular Material
Check Visibility of an Object with JavaScript
React Animation for Moving an Element from One Parent to Another
Adding Style Stored in a Variable Inside React Class
Elements Positioned Relatively Don't Move When the Dom Is Updated (IE6 and IE7)
How to Extract R, G, B, a Values from CSS Color
Applying More in Depth Selection to the :Host CSS Pseudo Class
How to Save an Image with CSS Filter Applied
How to Replay a CSS3 Animation in Reactjs
How to Pause CSS Transition Mid-Way
Semantic-Ui Modal Size Keeps Extending to the Height of a Page
Gulp with Gulp-Ruby-Sass: Error: ../Style.Css.Map:3:1: Unknown Word
How to Width-Wise Shrink-Wrap Content That Spans More Than One Line