gibatronic gibatronic - 5 months ago 31
CSS Question

z-index chrome bug

I'm experiencing a really annoying bug that seems to only happen on Windows and OS X: the z-index of an element whose parent has fixed position doesn't work on Chrome! I converted my odd situation to a simple code:

html:

<div id="mask">
&nbsp;
</div>

<div id="box">
<div class="below-mask circle">
should be below the mask
</div>

<div class="above-mask circle">
should be above the mask
</div>
</div>​


css:

body {
font-family: Verdana;
font-size: 9px;
margin: 0px;
}

#box {
position: fixed;
}

#mask {
position: absolute;
left: 0px;
top: 0px;
background-color: rgba(0, 0, 0, 0.5);
width: 100%;
height: 100%;
z-index: 9998;
}

.circle {
position: relative;
background-color: rgba(255, 204, 0, 0.75);
border-radius: 75px;
line-height: 150px;
margin: 50px;
text-align: center;
width: 150px;
height: 150px;
}

.above-mask {
z-index: 9999;
}

.below-mask {
z-index: 9997;
}​


sandbox: http://jsfiddle.net/gibatronic/umbgp/

I tested on Internet Explorer 9, Firefox 15, Opera 12.02 and Safari 5.1.7 on OS X and Windows and all of them displayed as expected.
I also tested on Ubuntu 12.10 and it worked just fine for every browser including Chrome!
I even tested on Kindle 4 browser and it worked!

I wonder if anyone knows any kind of fix to workaround this issue!

Answer

one800higgins's answer is along the right lines. The real answer is that on mobile WebKit and Chrome 22+, position: fixed always creates a new stacking context, even when z-index is auto. So the stacking context hierarchy looks like this:

  • document root (z-index 0)
    • #mask (z-index 9998)
    • #box (z-index 0)
      • .above-mask (z-index 9999)
      • .below-mask (z-index 9997)

That means that 9998 is never compared with 9999 or 9997 to determine stacking order. Instead, 9999 is compared with 9997 to determine which of .above-mask and .below-mask is further in front, and then once everything inside #box is stacked in that context, it's treated as a single layer at z-index 0 which gets stacked behind #mask at z-index 9998.

This also explains why @TheNextBillGates's answer of moving #mask inside #box works - because then #mask is in the same stacking context as .above-mask and .below-mask. I highly recommend the above link for more comprehensive details, and you should also see the announcement for the stacking change for fixed elements in Chrome.

Comments