iOS 5 Native Scrolling–Grins & Gotchas
by George White Tuesday, March 6th, 2012
When Apple released iOS 5 last year, one of the improvements included in Mobile Safari was the inclusion of support for scrolling of block elements with the CSS overflow:auto or overflow:scroll declarations. In addition, support for fancy and fast bounce-scroll behavior is provided with the inclusion of the -webkit-overflow-scrolling: touch vendor-specific declaration.
The inclusion of scrolling on clipped elements is great and goes a ways towards making it much easier to layout HTML5 pages and apps in a consistent manner, and closes the gap a bit between web and native behaviors. And it’s easy to implement.
For example, to add scrolling on an element with class="scrolling-element":
| 1 2 3 4 |
|
Fast scrolling, broken rendering
Unfortunately, Apple released a buggy implementation of -webkit-overflow-scrolling: touch. The problem is seems pretty awful at first: if you use the new native scrolling behavior on elements that use or contain children with position:relative, you may end up with some pretty gnarly rendering areas. This is particularly true for stuff that gets rendered off-screen.
Lucky for us, there is relatively (ahem) painless workaround. If you force Mobile Safari to use hardware acceleration when drawing the positioned elements, the rendering errors disappear. How do you do that? With a little 3D magic, via a no-move translation with this declaration: -webkit-transform: translate3d(0,0,0). Sprinkling this 3D fairy dust on your elements with position:relative and your rendering issues will vanish.
| 1 2 3 4 5 6 7 8 9 |
|
One thing I have found is that sometimes, you need to apply the hardware acceleration hack to all of the child elements inside the scroller. This turned out to be true on a very complicated faux table in our really big HTML5 iPad app. The solution there was to use a scope universal selector. This isn’t the most performant selector, but it gets the job done in a way that working with the individual elements just didn’t cut it.
| 1 2 3 |
|
Update: I have found since writing this that even the hardware acceleration hack doesn’t cure all rendering ills. On the aforementioned complex layout, which for various reasons mimics a table, some of the elements in the cells were rendering incorrectly even with translate3d(). The solution in this case was to fix the height of the elements. This is not ideal in all situations, of course, and I’ll be looking for alternatives in the future. Also, iOS 5.1 does not appear to fix the scrolling issues.
Filling the gaps
Another issue with the native scrolling in iOS 5 is backward and cross-browser compatibility. iOS 4 doesn’t support overflow scrolling or the native touch behavior; your elements won’t scroll at all with this technique before iOS 5. On other platforms, not every mobile browser support overflow:auto or overflow:scroll and support for -webkit-overflow-scrolling is even more unlikely as you move beyond iPhones and iPads. So, what to do about it?
Fortunately, there’s a pretty nice new poyfill, Overthrow, that can help plug the scrolling holes. Like all polyfills, Overthrow seeks to use the latest and greatest built-in support when it can, and fills in the gaps with Javascript implementations when the current browser isn’t up to the task.
Using Overthrow is pretty simple. Include the script file in your page and define a CSS class like this:
| 1 2 3 4 |
|
Overthrow will try to figure out if the current browser is capable of using the native implementation; if it can, the class overthrow-enabled will be added to the HTML element and the native implementation will be used, with all it’s fast, bouncy goodness. If not, Overthrow will use it’s own scrolling implementation, which is as fancy. But, hey, your stuff will still scroll!
Overthrow is fairly new and it’s likely to get better, especially if you fork it and lend a hand.
Hi, I think your 3rd Gist is hooked up wrong. Otherwise a succinct writeup, thanks.
Another non-JS fix is: https://github.com/joelambert/ScrollFix/issues/2
Corrected. Thanks for the head’s up.
Thanks, I ended up with gaps in a custom lightbox and now it is fixed!
Hi George, I almost went bananas trying to figure out what was wrong with a web app I’m developing. Triggering hardware acceleration fixes the problem (as in numerous other situations in mobile safari), fantastic. Thanks!
I don’t know why ios dont support iframe scrolling. I can’t scroll on iframe even with double finger gesture.
Hey hi George,
Your post help me to get the IOS scroll on my web pages. But I am facing a problem with my Custom jQuery build Popups. I am giving a class “.scrollable” to the div “content” of my popup. The 1st popup gets the scroll. But the 2nd Popup does not. When I browse it in iPad, using a “weinre” remote debugging tool, it seems that it has got the class “.scrollable”. But there’s no scroll applied. Another thing, I noticed is that when I change the orientation from landscape to portrait & vice versa with my popup open. The popup gets the scroll. Can u please put a light on this..?? Like where I am exactly going wrong?? Thanks in advance.
What about vertical scrolling, struggling to get a list to scroll… Any ideas?
Awesome post, George. I spent the whole morning trying to figure out why iOS was doing this to my overflow:auto
<
div>s. And finally, found this article and the fix.
Many thanks!
Kris,
Glad to hear this post helped you out.
G