25

Problem:

On iOS the z-index of a scrollable area is ignored when using -webkit-overflow-scrolling. If two objects with -webkit-overflow-scrolling overlap the lower one is scrolled instead of the one being displayed above.

How to reproduce:

Create two elements overlaying each other (with position: absolute for example), one of them having a higher z-index and add

.selector
{
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}

to both of them. Both elements should have enough content to be scrollable.

Additionally add

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="apple-mobile-web-app-capable" content="yes"> 
<meta name="apple-mobile-web-app-status-bar-style" content="black">

to your <head>. Then add the page to your home screen and launch it from there.

If you then try to scroll the upper element the element beneath is scrolled instead.

MCVE:

Alternatively just check out this pen. Launch the full version from your iOS device, add it to your home screen and launch from there.

Environment:

Tested on iPhone 5 and iPhone 6 with iOS 9.1 and iOS 9.3.2

Observations:

  • The issue only occurs when launching the page/app from homescreen (pinned app) or inside a Xamarin Webview (might have something to do with UIWebView and WKWebView)
  • After changing the device orientation (portrait/landscape) after page load the problem is fixed until the page is reloaded (maybe re-triggering layout fixed it?)
  • Changing the lower elements overflow-y to hidden via JS does fix the problem, however toggling overflow causes a repaint causing performance issues
  • Removing height: 100%; width: 100% from html, body fixes the problem as well, however those have to be set for percentage values to work properly

Needed is a proper solution / workaround to fix this issue without causing any troublesome side-effects. Also explanation of why this happens would be appreciated.

Aides
  • 3,643
  • 5
  • 23
  • 39
  • I've had similar z-index bugs if elements had 3d transformations applied. I have no iOS device around to test this at the moment, but you could try removing 3d transforms. – keaukraine Jun 08 '16 at 08:24
  • What exactly was your problem then? As far as I know there are two issues with z-index on iOS. One being that z-index elements are displayed in the wrong order and the one described above where the wrong item is being scrolled. – Aides Jun 08 '16 at 09:15

4 Answers4

11

Essentially, what you're experiencing is an iOS bug with -webkit-overflow-scrolling: touch;. In order to solve this bug, as per this answer, just add the following CSS styles to the scrollable div:

-webkit-transform: translateZ(0px);
-webkit-transform: translate3d(0,0,0);
-webkit-perspective: 1000;

So all in all, if you add the above styles to the styles for the scrollable class in your CSS, it should work. Tested on an iPhone 5s running iOS 9. Note that if you scroll down to the bottom or top of the scrollable section that is above everything else, it will start to scroll the body.

I believe that what those extra styles do is trick the iPhone into using the GPU, but remember that they're only necessary due to a bug with Safari - it's not your fault and these extra styles shouldn't really need to be included. But pop them into your CSS and it should work like a dream!

Community
  • 1
  • 1
Isaac Adni
  • 831
  • 4
  • 14
  • 29
  • I needed to add 0 transforms to the item that was not visible down the list.. but still this helped me geting there. kudos – csomakk Feb 27 '17 at 14:26
  • In addition to this, in my case the overlapping element required a `transform: translateZ(...px)` with a higher value than the scrolling element (the one beneath). Otherwise, when the scrolling element would go out of screen (i also have horizontal scroll) and a repaint happened, it would come out on top again, which was wrong. This answer got me there, thanks! – Teodor Sandu Jun 07 '18 at 09:54
2

Assuming you face the problem like them. Please, take a look at these post:

Hope this help!

Community
  • 1
  • 1
AnLT
  • 569
  • 8
  • 22
0

A really easy fix for this would be to toggle a class to the body on scrolling and target your scrollable windows. If you're scrolling .scrollA then toggle class scrollB to body and apply something like this Javascript/css or you could do it all with javascript, your choice.

Javascript

$('#targetDivA').on('scroll touch', function(){
   $('body').toggleClass('scrollB);

   //or use this to navigate to it
   //$(this).siblings().toggleClass(\'scrollB\')
})

CSS

body.scrollB .targetDivB {
    pointer-events: none;
    /*this eliminates the device from using any event until removed*/
}

Hope this helps you mate!

Caleb Swank
  • 619
  • 5
  • 17
0

Remove this property dynamically when have need. It's less complicated and do not cause side effects.