Baraka
Baraka

Reputation: 374

z-index treated differently on iOS when setting -webkit-overflow-scrolling: touch

I'm seeing some interesting z-index behaviour on iOS.

My sample code can be viewed here: https://jsfiddle.net/59mo8s16/4/

I need the #sidebar to be displayed in front of the #slide-in-tip. This is the case when viewed on Chrome (PC and Android) and Firefox (PC). However, on iOS Safari and Chrome, #slide-in-tip appears in front of #sidebar.

I've realised that removing -webkit-overflow-scrolling: touch from the CSS makes it appear as intended across all platforms/browsers. However, I need this in order to provide momentum scrolling for the #container div on iOS. Without it, you get that scrolling that stops as soon as you stop swiping, which provides a terrible user experience.

Any ideas on how to resolve this one? Ideally I'd like a CSS-only solution. Any significant restructure of HTML will cause me some major pain at this point. The sample is a really stripped back version of an already-complete website.

HTML:

html,
body {
  height: 100%;
  margin: 0;
  -webkit-overflow-scrolling: touch;
}

#top-bar {
  top: 0;
  width: 100%;
  z-index: 200;
  background-color: green;
  height: 85px;
  position: absolute;
}

#sidebar {
  float: left;
  padding: 30px;
  background-color: pink;
  position: fixed;
  width: 310px;
  left: 0px;
  z-index: 150;
  top: 85px;
  bottom: 0px;
  padding: 0;
  padding-bottom: 50px;
}

#container2 {
  min-height: 100%;
}

#main {
  padding-right: 20px;
  height: 100%;
  margin: 0;
  margin-left: 10%;
  line-height: 40px;
  text-align: right;
}

#container {
  height: 100%;
  margin: 0;
  position: absolute;
  width: 100%;
  overflow-y: scroll;
}

#container2 {
  padding-top: 75px;
}

#slide-in-tip {
  position: fixed;
  bottom: 0;
  text-align: right;
  width: 100%;
  z-index: 140;
  background-color: blue;
  height: 200px;
}
<div id="top-bar">
  top-bar
</div>
<div id="container">
  <div id="container2">
    <div id="sidebar">
      sidebar
    </div>
    <div id="main">
      long content - see js fiddle for actual long content
    </div>
  </div>
</div>
<div id="slide-in-tip">
  slide-in-tip
</div>

Upvotes: 4

Views: 2065

Answers (1)

BoltClock
BoltClock

Reputation: 724372

The documentation offers an explanation for the behaviour you're seeing:

touch
Native-style scrolling. Specifying this style has the effect of creating a stacking context (like opacity, masks, and transforms).

Since you cannot destroy a stacking context after creating one, an element outside of a stacking context cannot interact directly with elements within that stacking context, and you cannot move elements between stacking contexts without moving them physically, you won't be able to work around the stacking issues without restructuring your physical HTML.

Having said that, you shouldn't have to make significant changes to your structure. The best you can do is simply move #slide-in-tip into #container2 as a sibling of #sidebar and #main (where exactly you place it doesn't matter, as long as they are all siblings). For whatever reason, though, this seems to cause severe flickering on scroll in the simulator — I don't have a physical device to test this on, so you'll want to test this thoroughly.

The only CSS-based workaround I can offer is to shorten your #slide-in-tip by giving it a left offset equal to the width of #sidebar. Note that you have conflicting padding declarations in your #sidebar rule such that the width of #sidebar is actually 310px, not 370px. Unfortunately, if portions of #sidebar are transparent and you want #slide-in-tip to be seen through those transparent portions, this will not be an option either.

Upvotes: 2

Related Questions