jammypeach jammypeach - 5 months ago 66
Android Question

Browser scroll event doesn't fire often enough on iOS and Android devices

I'm developing a one-page site using jQuery, greensock and scollorama.

It doesn't exactly need to support mobile browsers but it would be nice if it would work on the iPad - so with that in mind I started testing on various mobiles and tablets.

The problem I ran into is that scrollorama relies on the scroll event being fired fairly often as this is what the animations are hooked into - however, when using a touch screen, the browsers only seem to fire the scroll event when you start the drag and when you stop - this is consistent across Opera Mini, Chrome, Safari, FF Mobile.

To get my page to atleast partially work, I need to come up with something that will let me fire the scroll event more often - does anyone know how?

P.S I've tried using iScroll as the scrollorama docs suggest, however that didn't work and instead broke the animations and made scrolling impossible - I'm sure the plugin itself works but it doesn't seem to work well with what I've already got. I'm looking for something less involved than a plugin, just a snippet to trigger the scroll event ideally.

TL;DR

Devices with touch screens seem to only fire the javascript scroll event once or twice during a drag. Is there a simple patch I can do in JS or jQuery which will fire the scroll event more often?




Update: I've tried hooking into the touch events and triggering browser scroll with them like so:

$(document).on('touchstart touchend touchmove', function(){
$(window).trigger('scroll');
});


This seemed to give me better results on Android using Firefox, although I don't think it's firing as often as I'd like it's better than nothing.

I'll test in other browsers and see if this helps.

Update 2:

The above code helped alot on FF on Android, but not on iPhone. I tried adding handlers for gesture events that iPhone fires, but no change.

$(window).on('touchstart touchend touchmove mousewheel touchcancel gesturestart gestureend gesturechange orientationchange', function(){
//alert($(window).scrollTop());
$(window).trigger('scroll');
});

Answer

Pre-iOS 8:

It's not an issue of the scroll event being fired enough. Instead, browsers on iOS stop refreshing (i.e. "repainting") the screen while in the middle of a scroll gesture.

Safari WebKit, which is the HTML rendering component that is mandatorily used in all iOS browsers per Apple's policy, halts repainting during scroll gestures to conserve battery life and reduce heat. Note that JavaScript does continue to function normally in the background during a scroll gesture, even if the screen can't reflect any real-time changes that were made to the DOM during a scroll gesture. As soon as the gesture ends, a paint event is immediately fired, and the screen updates. However, timer loops, such as those that are setup via setInterval, do not fire during scroll gestures.

It's also worth noting that if you move your fingers very slowly when initiating a scroll, the scroll gesture doesn't take effect until after you've moved your finger approximately 10 pixels away from its starting position. During movement within this 10-pixel radius, the screen continues to be refreshed instantaneously. The moment that WebKit decides that your finger has moved far enough to initiate scrolling, screen refreshes are disabled until the scrolling gesture ends.

The reason this problem doesn't affect "some" web pages or JavaScript libraries is that they effectively "freeze" the page's scrolling, and instead emulate scrolling by intercepting touch events and then adjusting the body.scrollTop property accordingly. They freeze the page's scrolling by attaching an event handler to the onscroll event, and issue an event.preventDefault() command from within the event handler.

iOS 8 and later:

Apple is making the scroll event more fluid in iOS 8:

http://developer.telerik.com/featured/scroll-event-change-ios-8-big-deal/