Sunday, June 26, 2011

Implications of iOS 5 webkit-overflow-scrolling

When news of iOS 5 improvements first came out, we were told that Mobile Safari would support fixed position elements and some rudimentary overflow:scroll improvements. I wrote about why, even with these improvements, custom scrolling would still be required. Fortunately for all of us, Apple had some better news to share when the second beta of iOS 5 came out. Finally, we can have native style scrolling in webapps with some simple CSS.

.scrollable {
  overflow-y: scroll;
  -webkit-overflow-scrolling: touch;
}

This improvement will be a very powerful tool for mobile web developers. It will make it significantly easier for just about any developer to throw together a really slick looking application. What was previously hundreds of lines of complex JavaScript to animate the page is now 2 simple lines of CSS.

What else will change?

Scrolling Quality

Up until now, almost every scrolling library has tried as hard as possible to replicate iOS native scrolling. As far as I can tell, the only reason that Scrollability even exists is because Joe Hewitt figured he could do a better job of replicating native scrolling than iScroll. With this now natively supported by Mobile Safari, we can all stop worrying about these discrepancies and focus on real work :)

Something less talked about is the rending and GPU overhead that is caused by custom scrolling implementations. Often all of the transforms introduces a lot of flashing in the application when content is re-rendered. Scrolling also gets slower the larger the DOM gets. Presumably with the native support all of these problems will go away, and the user will just have a consistently smooth scrolling experience.

Pull down to refresh

Two weeks ago I wrote about the various pull to refresh implementations on the internet and why I wasn't happy with any of them. Since then, Mobile Gmail pushed an update that includes a really slick pull to refresh widget. Every pull to refresh library that I know of right now is implemented as an add-on to some scrolling library. This is because the pull to refresh components have a high level of interaction with the scrolling components. It is likely that everyone is going to have to rewrite their pull to refresh code to work in the absence of custom scrolling.

I think it won't be at all difficult to rework the widget to work properly, but we might see some applications take a bit longer to migrate to the built in scrolling because of issues like this.

Sticky table headers

Sticky table headers could be a little more troublesome depending on exactly how the built in scrolling is implemented in Mobile Safari. For an example of what I am talking about, check out the menu page on Mobile Gmail, how the list section headers stay fixed at the top and animate away as another header approaches. Like pull to refresh components, sticky table headers implementation requires tight integration with the custom scrolling library it is built on top of.

In Mobile Gmail, the positions of the sticky headers are recomputed on every touchmove event, and on a repeating interval if momentum is in progress. The same can easily be done with the built in scrolling if the browser publishes accurate scroll events. If not, we can maybe estimate when the page might be flinging based on touch events.

Tap to top

Tap to top is a standard gesture recognized by most (all?) iOS native applications that will scroll the current view to the top. When a user taps the top bar in Mobile Safari, the page will scroll to the top and the URL bar will become visible. Ideally the overflow:scroll element  on the page will also be scrolled to the top. Mobile Gmail and Scrollability both support this gesture by listening to scroll events, and determining if the scroll event was from the user dragging the page or tapping the top (based on time of last touch event anywhere in the document).

It is possible that the new built in scrolling will natively support scrolling the overflow:scroll areas to the top, but that seems unlikely. If they in fact do not, then devs might have to use some hacks to continue supporting a tap to top feature. We can still detect the tap to top gesture just as easily, however you can't apply a webkit-transition to the scrollTop feature (now required to change the scroll position). It might be necessary to change the transform to do something like this:

function tapToTop(scrollableElement) {
  var currentOffset = scrollableElement.scrollTop
  
  // Animate to position 0 with a transform.
  scrollableElement.style.webkitTransition =
      '-webkit-transform 300ms ease-out';
  scrollableElement.addEventListener(
      'webkitTransitionEnd', onAnimationEnd, false);
  scrollableElement.style.webkitTransform =
      'translate3d(0, ' + (-currentOffset) +'px,0)';
    
  function onAnimationEnd() {
    // Animation is complete, swap transform with
    // change in scrollTop after removing transition.
    scrollableElement.style.webkitTransition = 'none';
    scrollableElement.style.webkitTransform =
        'translate3d(0,0,0)';
    scrollableElement.scrollTop = 0;
  }
}

2 comments:

  1. Thanks for this post.

    Could you talk a little bit more about the GPU Rendering overhead caused by loading an iScroll?

    ReplyDelete
  2. There is an issue with -webkit-overflow-scrolling when you zoom in the page. If you have a block with overflow along with normal blocks, contents of the block with overflow will significatnly loose in quality when you zoom in page, as if the contents is JPEG image wih poor quality. While 'normal' content outside of block with overflow is zoomed in correctly.
    This issue only occurs when -webkit-overflow-scrolling is set to touch.

    ReplyDelete