Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
mattsahr opened this Issue Nov 17, 2011 · 23 comments

Comments

Projects
None yet
8 participants
@mattsahr
Copy link

mattsahr commented Nov 17, 2011

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.

@cheeaun

This comment has been minimized.

Copy link

cheeaun commented Nov 17, 2011

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

@joelambert

This comment has been minimized.

Copy link
Owner

joelambert commented Nov 21, 2011

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?

@bjrn

This comment has been minimized.

Copy link

bjrn commented Feb 1, 2012

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

@bjrn

This comment has been minimized.

Copy link

bjrn commented Feb 1, 2012

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

@thebird

This comment has been minimized.

Copy link

thebird commented Feb 15, 2012

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 :)

@bjrn

This comment has been minimized.

Copy link

bjrn commented Feb 15, 2012

@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/

@thebird

This comment has been minimized.

Copy link

thebird commented Feb 15, 2012

@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.

@bjrn

This comment has been minimized.

Copy link

bjrn commented Feb 15, 2012

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

@thebird

This comment has been minimized.

Copy link

thebird commented Feb 15, 2012

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

@bjrn

This comment has been minimized.

Copy link

bjrn commented Feb 15, 2012

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.

@foliomob

This comment has been minimized.

Copy link

foliomob commented Mar 8, 2012

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!

@bjrn

This comment has been minimized.

Copy link

bjrn commented Mar 8, 2012

@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

@foliomob

This comment has been minimized.

Copy link

foliomob commented Mar 8, 2012

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!

@foliomob

This comment has been minimized.

Copy link

foliomob commented Mar 8, 2012

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

@nevir

This comment has been minimized.

Copy link

nevir commented May 7, 2012

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

@nevir

This comment has been minimized.

Copy link

nevir commented May 7, 2012

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.

@cheeaun

This comment has been minimized.

Copy link

cheeaun commented May 7, 2012

@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/

@nevir

This comment has been minimized.

Copy link

nevir commented May 7, 2012

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

@cpojer

This comment has been minimized.

Copy link

cpojer commented Jun 6, 2012

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.

@cheeaun

This comment has been minimized.

Copy link

cheeaun commented Jun 6, 2012

@cpojer would need to see a demo page :)

@cpojer

This comment has been minimized.

Copy link

cpojer commented Jun 6, 2012

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.

@bjrn

This comment has been minimized.

Copy link

bjrn commented Jun 6, 2012

@cpojer, most likely it is because of the -1px bottom margin that is used to fix the case where the content is shorter than the container. It also scrolls to the top when the DOM elements is updated inside the scroll area, nasty indeed... I went for a somewhat different approach in a recent iPad project, will put together an example of that solution tomorrow, and see if that works better for you as well.

@bjrn

This comment has been minimized.

Copy link

bjrn commented Jun 7, 2012

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 Oct 3, 2012

Closed

Scrolling #12

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.