Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

another solution -- nested divs with overflow:touch #2

Open
mattsahr opened this Issue · 23 comments

8 participants

Matt Sahr Lim Chee Aun Joe Lambert Björn Rixman Brad Birdsall Shawn Taylor Ian MacLeod Christoph Pojer
Matt Sahr

I stumbled upon a way to use native scroll, but sidestep the document-bounce behavior. I tested it with an iPad 1, using IOS 5.1.

If you build internal scrolling divs and you can declare explicit height/width for them, you can achieve this without javascript.

This approach uses a set of 3 nested divs. The innermost div is tall enough to kick in the scrolling behavior, the middle div is smaller than the outermost div, and I guess the outermost kills the propagation by evaluating for touch-scroll and coming back with "nothing to do" Or, I think that's what's happening.

OuterDiv -- fixed height, width, overflow-scrolling: touch;
MiddleDiv -- fixed height width, overflow-scrolling: touch; fits inside OuterDiv
InnerDiv -- fixed height width, bigger than MiddleDiv, so it kicks in the overflow behavior

Here's an example:
https://gist.github.com/1372229

This example does the triple-nested trick twice. The inner 3-wrapper-set uses no javascript (height and width are explicit CSS declarations). The outside 3-wrapper-set uses javascript to fetch the document height, so that it can be full-window-size. This approach allows native internal scrolls AND reaps the benefits of killing page-bounce for the overall document.

Before IOS 5 native internal scroll, the usual method to kill the page-bounce was....

document.body.addEventListener('touchmove', function(e) {
    // This prevents native scrolling from happening.
    e.preventDefault();
}, false);

And then you would have to build your own drag behavior.

I dunno how robust this hack is, I fear an upgrade to Safari might... "fix" this. But at the moment, it seems like you get the desired effect (internal scroll, no document bounce) almost for free.

Lim Chee Aun

Wow, this actually works (tested on Mobile Safari, iOS5, 3GS). Here I did a simplified testcase http://jsbin.com/oheqec/2

Joe Lambert
Owner

Thanks Matt, this does indeed seem to do the trick!

I think this is probably the best solution we have until Apple fixes it natively. Have you tried to create a JavaScript that can replicate the DOM structure required so it can be applied like ScrollFix.js?

Björn Rixman

I think I might have found an easier way to solve this issue, which does not require setting explicit heights for the scroll panels, but rather relies on flex-boxes for filling up available space... see this gist:
https://gist.github.com/1719717

have tested it on iOS5.0.1 on an iPad2

Björn Rixman

here's an URL to the example page: http://rixman.net/demo/scroll/

Brad Birdsall

I started playing around with @mattsahr's solution, which is amazing btw, and simplified it a bit. I tried taking everything out expect for what is absolutely required.

http://fiddle.jshell.net/bradbirdsall/5uTy9/show/light/

Source on jsFiddle

I'm currently working on some mobile web templates that will hopefully;) use this implementation. Great work guys!

@joelambert this is the real deal :)

Björn Rixman

@bradbirdsall nice! so we don't even need margin-bottom:-1px anymore?

The only issue with your solution is that we still get rubber-banding when the content is smaller than the viewport:
http://fiddle.jshell.net/bjrn/mtpsa/show/light/

The negative bottom-margin seems to solve this,
but I think I also have one more wrapper element in this working example, here:
http://rixman.net/demo/scroll/1/

Brad Birdsall

@bjrn I'm not following, can you put up a test case that shows what you mean? Like using the code I used but with the specific edge case you're talking about. I can't seem to reproduce it.

Björn Rixman

the jsfiddle I linked to previously is showing the issue: http://fiddle.jshell.net/bjrn/mtpsa/show/light/

it's basically just a fork of your example, but with only two div elements inside. try scrolling inside that example to see the document-bounce behaviour reappear

Brad Birdsall

Ahh I see. Thanks for explaining. Can we solve this with just two wrapping elements?

Björn Rixman

I think it might need a third one actually. I have a wrapping element here, and it works fine: http://rixman.net/demo/scroll/1/

I tried putting margin-bottom:-1px on sF-wrap in your example, see here:
http://fiddle.jshell.net/bjrn/mtpsa/10/show/light/

it then works most of the time, but if you scroll upwards first, rather than down, it bounces.

Shawn Taylor

I've been looking for a simple way to persistently hide the url bar on iPhone (beyond just position:fixed; top:0; since that's not persistent enough), which lead me here. I didn't know native scrolling was my solution, but it was. I just needed it for iPhone, so took parts of what you guys did, made is as simple as possible, and put it here: https://gist.github.com/2000635.

Demo is here: http://dl.dropbox.com/u/838533/Misc/20120307-urlandscrollfix.html

Thanks so much for the awesome start!

Björn Rixman
bjrn commented

@foliomob - I think the best solution for "re-hiding" the url bar when switching between landscape and portrait would be to listen to the orientationchange event and scroll to top when that happens. Scott Jehl has written a good article of the intricaties of url bar hiding http://24ways.org/2011/raising-the-bar-on-mobile.

Lim Chee Aun has a solid implementation (at least for iOS5+) of url bar hiding in overflow-scrolling:touch layouts in his hacker news mobile app: https://github.com/cheeaun/hnmobile

Shawn Taylor

Thanks @bjrn - Lim Chee's hnmobile is actually what got me started, but it's way over my head. I'll check out Scott Jehl's article. Thanks!

Shawn Taylor

@bjrn Awesome thanks! Got hide url on orientationchange working and added ontouchstart for good measure.

Ian MacLeod
nevir commented

One other gotcha from this approach is that it breaks scroll to top behavior when tapping the status bar

Ian MacLeod
nevir commented

Turns out you can get scroll to top behavior w/ a bit of JS magic (that is almost definitely a browser bug):

Edit: Nevermind; this causes mobile safari to crash randomly

http://jsfiddle.net/PABVz/

By omitting overflow: auto on the outer div, and inserting it via javascript on touchstart, you get the best of both worlds. Strangely, you don't even have to unset it.

Lim Chee Aun
cheeaun commented

@nevir I've tried it, seems to crash Mobile Safari on my iPhone 4S when I tap on the status bar. I've modified the fiddle a little to prevent viewport scaling and add another bunch of text to scroll the whole web page: http://jsfiddle.net/PABVz/2/

Direct demo link: http://fiddle.jshell.net/PABVz/2/show/light/

Ian MacLeod
nevir commented

Damn, yeah, I'm seeing crashing on my phone & after a lot of tapping on my iPad too. I'll play around some more :)

Christoph Pojer
cpojer commented

I'm using the version by @bjrn and running into a problem when I'm removing elements inside of the container via JavaScript where it scrolls to the top. Did anyone run into this and find a fix?

Otherwise it seems like the perfect solution. Mhh.

Lim Chee Aun

@cpojer would need to see a demo page :)

Christoph Pojer
cpojer commented

I uploaded an example here: http://jsbin.com/agozej

Expand the list, scroll down and click on any item. It will remove the item and scroll to the top. Nasty stuff.

Björn Rixman
bjrn commented
Björn Rixman
bjrn commented

I made a quick example with an alternative approach:
http://fiddle.jshell.net/e79jY/show/light/

code is here: http://jsfiddle.net/bjrn/e79jY/

basically there are two alternatives to the margin-bottom:-1px fix I came up, but both require javascript in order to work. The main issue with the -1px solution is that whenever the dom inside the scrolling element changes, it scrolls back to top, which, in most cases is a clear no-go.

in the iPad webapp we're developing there are several scrollview areas on screen, and the easiest wat to prevent oversall rubber banding effect was by adding $(document).on('touchmove', function(e){e.preventDefault(); });

this however also prevents native scrolling inside the scrollview, so I added a flag to not do the preventDefault() if there was a touchstart inside .scrollview-content (and scrollview-content was taller than its parent container).
that is the commented out version inside the source code. When the content is shorter than the scrollview area, it is totally stale, which makes it feel a little less natural. An alternative approach is to set the min-height to 2px more than the height of the container at touchstart, which is what the example is showing.

Would be great if you have any suggestions how this can be improved and optimized upon - this is merely a quick functional example...

hallodom hallodom referenced this issue in zestia/glide
Closed

Scrolling #12

Gino onigetoc referenced this issue in 01org/appframeworkMVC
Closed

Native scroll bounce #17

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.