This:
$('body').on('touchmove', function(e) { e.preventDefault(); });
Works, but will disable scrolling throughout the whole page, which is far from ideal.
This:
$('*').on('touchstart', function(e){
var element = $(this).get(0);
if ( element.scrollTop <= 0 ) element.scrollTop = 1;
if ( element.scrollTop + element.offsetHeight >= element.scrollHeight ) element.scrollTop = element.scrollHeight - element.offsetHeight - 1;
});
Works on pages that have a scrolling area. However when there is nothing to scroll it will again show the rubber-band.
So my question:
How can you disable the rubber band effect and still keep the -webkit-overflow-scrolling
areas scrollable?
[Update]
Best Solution
Disable scrolling on all non-scrollable elements such as a tab bar or a navigation bar.
anElement.addEventListener('touchmove', function( event ){ event.preventDefault() };
Attach a scroll handler to the scrollable elements such as the main content.
anElement.addEventListener('touchstart', function( event ){
if( this.scrollTop === 0 ) {
this.scrollTop += 1;
} else if( this.scrollTop + this.offsetHeight >= this.scrollHeight ) {
this.scrollTop -= 1;
}
}
Based on @Mark's answer, we came up with this alternative, which seems to work. Replace
.page_list
with the class names of scrollable items.Here's a solution that uses jQuery and Hammer.js (jquery-implementation). That's two libraries, but if you're working on mobile, chances are you'll want to include Hammer anyway.
For every drag-event that bubbles to the top (so non-scrolling drag-interactions can use stopPropagation) the handler checks if it bubbled through any elements with class=scrolling, if so, whether the user is scrolling within the allowed boundaries of that scrollContainer and only then does it permit native scrolling.
To kill drags via pinch etc.; escape as necessary to allow zooming if your view is user-scalable
Tested on ios7/safari, android4.3/webview and android4.3/firefoxMobile25 and the only solution that didn't break.
I wrote, in my opinion, the best solution for this problem. It will disable scrolling in general unless the element has y scrolling.
Ran into the same issue recently with a SPA where the
<body>
rubber-banding was detracting from the experience, but I needed scrolling in sub-areas. Many thanks to dSquared's suggestions, as Method 1 worked best for me. Here is my small expansion of his suggestion that I implemented in a project for work that looks all the way up the tree to find any elements (not just divs) that have a.scroll
class on it:And here is what the CSS looks like:
You only need one library (jQuery or Zepto) and you get native scrolling with momentum and no rubber-banding on the body. Also, I've added the translateZ to fix some issues I've had with elements disappearing during scrolling and it can be used to GPU accelerate your elements.
BUT (and this is a big but), as dSquared points out, the whole page rubber-bands when the scroll element is at its limit and attempted to scroll further. Personally, I consider this a failure so I'm continuing to work on it, just wanted to pitch in on trying to figure this out. Adding a check along the lines of the OP's code might be the answer, but I haven't tried it.
UPDATE (10/7/12):
After lots of work, I've gotten the following code working perfectly in iOS6 (haven't tested in anything else). No rubber-banding on the body, no more issues when at the limit of the scroll area, and it has native scrolling performance throughout. It's obviously a lot more code that originally, but I think this will give the behavior closest to the OP's goals.
Unfortunately there isn't a 'magic bullet' fix for this as the rubber-band scrolling on Mobile Safari is an inbuilt 'feature' of the browser itself. By using any default scrolling mechanism provided by the browser, you will end up with the rubber-band scrolling to some degree.
There are two ways I would suggest to tackle this:
Method 1
Bind to the
touchmove
event on the</body>
element and check the target of thetouchmove
event to see if you want it to fire or not like so:HTML
JS
JSFiddle Example Here
This method uses the default scrolling of the browser, however it has the drawback that you will still have the rubber-band scrolling when at the top or bottom of the scroll
</div>
.Method 2
Bind to the
touchmove
event of the</body>
element as before, however in this case we prevent Alltouchmove
events and rely on the excellent iScroll 4 plugin to handle the scrolling, like so:HTML
JS
JSFiddle Example Here
This is my preferred method as it blocks all rubber-band scrolling and provides a nice scrolling area, however it relies on the use of a plugin.
I hope this helps
Just add a
-webkit-overflow-scrolling: auto;
to the div you want to prevent from bouncing