Bug Fix for Overflow Scrolling on Orientation ChangeProgramming

Mobile touch scrolling on in-page elements has been a pain point since I started working with mobile and responsive sites. There are a lot of js libraries out there to help with this, but no matter how well they’re written you run into a few fundamental issues, such as:

  • Horizontal scrolling being paused by unintended vertical scrolling.
  • A hit to your js load by including a (usually fairly large) lib.

So naturally I was glad to see -webkit-overflow-scrolling: touch introduced. Since it rolled out across iOS I’ve been pushing for it whenever possible (Android so far will scroll as well when configured properly, just not with momentum). Sometimes it’s a battle to convince your team and/or leadership that having clean scrolling is more important then position snapping and some of the goodies js libs include, but in the end I’ve found this to be a winnable fight.

Since I’ve been rolling this functionality out across a few projects I noticed a bug related to orientation change. Basically if your scrolling content overflows in portrait view, but not landscape view you lose scrolling all together if you go to portrait from landscape at any point.

  1. Open your page in portrait; Overflow scrolling works great.
  2. Switch to landscape; If your content isn’t large enough to scroll it wont. This is what you’d expect.
  3. Switch back to portrait; Overflow scrolling no longer works.

The best solve I’ve found is a tiny snippet of js that’s relatively un-intrusive and equally hack-ish.

  • Give all your overflow scrolling elements a common class; I like “.scroll-pane”.
  • Add a listener to the “orientationchange” event.
  • In your handler iterate over all your “.scroll-pane” elements and force an inline style of “-webkit-overflow-scrolling” to “auto”, and “overflow” to “hidden”.
  • Use a setTimeout or requestAnimationFrame to undo the code in the next render frame.
  • In the timeout/renderFrame handler reset ”-webkit-overflow-scrolling” to “touch”, and “overflow” to “auto”.
(function(document, window) {
	
	// set scrollingElQuery to a class included on all your overflow-scrolling elements
	
	var scrollingElQuery = '.scroll-pane',
		timeout,
		
		resetScrollPanes = function(e) {
			
			var scrollingElements = document.querySelectorAll(scrollingElQuery),
				i = 0;
			
			/**
			 * Clear timeout so we do not have overlap if user changes orientations
			 * back and forth quickly.
			 */
			
			clearTimeout(timeout);
			
			for( ; i < scrollingElements.length; i++) {
				
				scrollingElements[i].setAttribute('style',
						'-webkit-overflow-scrolling:auto;overflow:hidden;');
			}
			
			timeout = setTimeout(function() {
				
				for( i = 0; i < scrollingElements.length; i++) {
					
					scrollingElements[i].setAttribute('style',
						'-webkit-overflow-scrolling:touch;overflow:auto;');
				}
			}, 10);
		};
	
	window.addEventListener('orientationchange', resetScrollPanes);
		
}(document, window));

Gist here.