October 14, 2011 13

A (partial) fix for iOS5 overflow scrolling (ScrollFix.js)

By

Update: Unfortunately this does not 100% solve the problem, the script falls down when handling touch interactions when a scrolling section is bouncing/rubber banding. I don’t think this issue can be worked around (but would love to be proved wrong!). As such, I don’t advise the use of overflow: scroll for web apps until Apple provide a fix, I’d recommend continuing to use iScroll or Scrollability in the meantime!


One of the things I was most looking forward to in iOS5 was the added support for overflow: scroll and the associated -webkit-overflow-scrolling: touch.

After a bit of use, there is at least one issue with the implementation that makes it difficult to use for full screen web apps. Fortunately there is a work around.

The newly supported overflow:scroll is a great addition to Mobile Safari’s arsenal and works well except under the following conditions:

  • The scroll area is at the top and the user tries to scroll up
  • The scroll area is at the bottom and the user tries to scroll down.

In a native app, you’d expect the content to rubber band but in Safari the whole page is scrolled instead.

Enter ScrollFix.js, a small script that works around this problem.

ScrollFix works around this by manually offsetting the scrollTop value to one away from the limit at either extreme, which causes the browser to use rubber banding rather than passing the event up the DOM tree.

To better demonstrate the problem (and solution) here are a couple of videos:

iOS5 overflow scrolling without ScrollFix.js

iOS5 overflow scrolling with ScrollFix.js

ScrollFix is a work in progress (there are still bugs!) and can be downloaded for free from GitHub. Please contribute code fixes or open tickets for discussion.

  • Aron Allen

    Hi, I have been wrestling with overflow: scroll, and -webkit-overflow-scroll: touch. I have an app with a header and a content area, on the touchmove event on the header, I call preventDefault, and on the touchmove event on the scroll area, I call preventDefault, but only if the scrollTop i min or max. This partly solves the problem, but it has some nasty side-effects, there is no rubber-banding on the contained div. I am also facing the same issue as you, namely that if you scroll fast upwards twice, it will scroll the document.

    Prevent default does some magic, but sadly I do not think it is possible to trigger it at the right time, and for the right element. Have you filed a bug to Apple?

  • K0st4s

    Joe, can you host a demo for us to eperience it! :)

  • http://www.joelambert.co.uk Joe Lambert

    A bug has been posted but not by me (Cubiq), I’ve also discussed it with the WebKit team on Twitter.

    I’ll likely also post a bug report to reinforce the issue

  • K0st4s

    Joe. Can you host the demo files? I want to look into your touch functions that you are using for the cells. Thanks in advance!

  • http://www.joelambert.co.uk Joe Lambert

    Hi, here’s a live version of the files I’ve uploaded to the GitHub repo:

    http://joelambert.github.com/ScrollFix/

    Its a reduced test case to show what ScrollFix can (and can’t) do. It doesn’t do anything that a real list ought to but hope it helps.

  • http://www.facebook.com/alinkous Aaron Linkous

    I have a similar problem with my web app, however how could this script be changed to solve horizontal scrolling?

  • http://www.joelambert.co.uk Joe Lambert

    This should be doable, the script just does some simple maths to work out if the scrollable section is at either extreme (either top or bottom) and in which case just offsets the scroll value so as to prevent container element capturing the touch event.

    Try swapping scrollHeight for scrollWidth and offsetHeight for offsetWidth etc, let me know how you get on.

  • http://www.facebook.com/alinkous Aaron Linkous

    I got it working somewhat, It doesnt bounce but once in either direction. Going to have one of our backend developers take a peek at it and see if he can improve on it, and I’ll post up the results

  • K0st4s

    If you don’t mind then, could you upload what you show in the demo video? :)

  • http://www.joelambert.co.uk Joe Lambert

    Sorry no can do, the code in the demo uses a framework I’m not able to make available. The way it uses ScrollFix is just the same as the example code though.

  • http://twitter.com/StudioKong Koen Veestraeten

    Hi Aron, I think it’s easier to prevent the default behaviour for the document by using preventDefault() and to enable touch events for specific elements on the document by using stopPropagation(). Using stopPropagation will prevent the event from bubbling up the DOM tree and as a result only the specified elements will have the rubber banding effect if you apply Joe’s ScrollFix to them (thanks for sharing Joe!). I made a quick demo for testing; here a live version: http://studiokong.be/scrolltest/. But, I also would consider this a bug so hopefully they’ll fix this soon.

  • Remuz

    Hi joe, I try to implement it in an iframe. But it seems not working. Here my example code. There was no scroll i found.

                                                   body {                margin: 0px;             }             #frameeditor{                                 position:fixed;                 overflow: scroll;                 -webkit-overflow-scrolling: touch;                                    }                        

                   

                                  

                           // Add ScrollFix             var scrollingContent = document.getElementById(“frameeditor”);             new ScrollFix(scrollingContent);                    

               

    Is there something wrong with my code?

  • http://nativeimaging.com/ Native Imaging

    I’ve test hundreds of touch-scroll scripts and plugins, and CSS3, but nothing actually works correctly. the “-webkit-overflow-scrolling:” doesn’t actually do a thing. Ive tested it on every system out there, but really, i see this style doing nothing. I cannot even find one single javascript that can handle touch-swipe correctly at all. Does anyone know of a good script that is actually working?