My understanding is that z-index elements are only stacked with their siblings. I've also read that z-index "doesn't work" with position: fixed
. However, I'm using the two together and it happened to do exactly what I wanted it to; and I want to understand why.
I have a blocking div that needs to cover everything in the page except one element. The element is not a sibling of the blocker, which I thought would make it impossible, but it worked. What rule is being exploited here, and how can I predict if it will work in other browsers?
.top {
background-color: yellow;
}
.yes {
position: relative;
z-index: 10;
background-color: blue;
}
.no {
position: relative;
z-index: 1;
background-color: red;
}
.blocker {
position: fixed;
z-index: 5;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .7);
}
<div class="top">
<button class="yes">
Yes
</button>
<button class="no">
No
</button>
</div>
<div class="blocker">
</div>
Every non-positioned box belongs to the same stacking context that's established by the closest ancestor that meets any of the criteria listed here, or the root element if there is no such ancestor. This means that elements don't have to be siblings of one another in order to participate in the same stacking context. They may share a distant ancestor (in HTML, every element descends from the root element), but they don't have to share a parent.
.top
does not establish a new stacking context for its descendants .yes
and .no
as it is non-positioned and its z-index is auto. Therefore, .yes
, .no
and .blocker
all participate in the same stacking context — the root stacking context. As a result the mere fact that .yes
has a higher z-index than .blocker
causes it to be painted in front.
Note that while each of .yes
, .no
and .blocker
does establish its own stacking context, the stacking contexts they establish are not pertinent here; it's the stacking context that they participate in, and they all participate in the same root stacking context.