I know stacking order without z-index has been discussed before, and I understand that positioned and non-positioned elements are treated differently in default stacking order.
However, of all the documents I have read, I still feel very confused whenever it says "in order of appearance", or "descendant non-positioned/positioned blocks", or even "tree order" etc.
I am wondering what is the precise meaning of the rules in this document - in particular, the impact of parent-child hierarchy on stacking order. For example, what happens if a positioned parent has a non-positioned child, or a non-positioned child has a positioned parent?
I have created two examples for demonstration, the css rules are the same across them:
The first one
.non-positioned {
position: static;
padding: 5px;
}
.positioned {
position: absolute;
padding: 5px;
}
.big {
width: 200px;
height: 100px;
}
.medium {
width: 60px;
height: 60px;
}
.margin-20 {
margin: 20px;
}
.bg-red {
background-color: rgba(255, 0, 0, 0.8);
}
.bg-blue {
background-color: rgba(0, 0, 255, 0.8);
}
.bg-green {
background-color: rgba(0, 255, 0, 0.8);
}
.bg-yellow {
background-color: rgba(255, 255, 0, 0.8);
}
.bg-black {
background-color: rgba(0, 0, 0, 0.8);
}
<div class="positioned big margin-20 bg-red">
<div class="positioned medium margin-20 bg-black"></div>
<div class="non-positioned medium bg-green"></div>
</div>
<div class="non-positioned big bg-blue">
<div class="non-positioned medium bg-yellow"></div>
</div>
Questions I have here are mainly about the green block:
- why the non-positioned green block is on top of non-positioned blue and non-positioned yellow block? In what order definition would green block comes after both blue and yellow?
- why the non-positioned green block is even on top of the positioned red block?
The second one
.non-positioned {
position: static;
padding: 5px;
}
.positioned {
position: absolute;
padding: 5px;
}
.big {
width: 200px;
height: 100px;
}
.medium {
width: 60px;
height: 60px;
}
.margin-20 {
margin: 20px;
}
.bg-red {
background-color: rgba(255, 0, 0, 0.8);
}
.bg-blue {
background-color: rgba(0, 0, 255, 0.8);
}
.bg-green {
background-color: rgba(0, 255, 0, 0.8);
}
.bg-yellow {
background-color: rgba(255, 255, 0, 0.8);
}
.bg-black {
background-color: rgba(0, 0, 0, 0.8);
}
<div class="positioned big margin-20 bg-red">
<div class="positioned medium margin-20 bg-black"></div>
<div class="non-positioned medium bg-green"></div>
</div>
<div class="non-positioned big bg-blue">
<div class="positioned medium bg-yellow"></div>
</div>
My questions here is: why the positioned yellow block is on top of positioned red and black? It seems straightforward when looked in isolation, but when looked together with the 1st fiddle, what confuses me is that the non-positioned blue parent of the yellow block does not seem to have any impact on its stacking order, while in the 1st example, the positioned parent of green block seems to promote the stacking order of the green div to a higher value.
Edit
After going through all the posts (and the links, specs) provided by others, I managed to figure it out with help of the elaboration here
What I feel important is the rule No.8:
All positioned descendants with 'z-index: auto' or 'z-index: 0', in tree order. For those with 'z-index: auto', treat the element as if it created a new stacking context, but any positioned descendants and descendants which actually create a new stacking context should be considered part of the parent stacking context, not this new one. For those with 'z-index: 0', treat the stacking context generated atomically.
It basically means that positioned parent, even without z-index, effectively creates a stacking context but only for its non-positioned child elements.
To visualize it, the rendering tree is something like:
And the tree of the stacking is:
dotted rectangles indicate stacking context (effect).
The positioned red div creates a stacking context effect for its non-positioned child green, but its positioned child black still participates in the parent stacking context which is defined by root node html. Black div comes later because the preorder depth-first traversal has to visit red node first. Same for blue and yellow. Blue and yellow comes before others because they are non-positioned.
Basically I am just looking for evidence in the specification that supports the statement: by default (no z-index or explicit stacking context creation involved), child element never goes below its parent. And that holds because:
- if both parent and child are non-positioned, tree order (preorder depth first) ensures child is on top.
- if both parent and child are positioned, tree order (preorder depth first) ensures child is on top.
- if parent is non-positioned but child is positioned, they both participate in some parent stacking context, and no matter what that is positioned element has higher stacking order.
- if parent is positioned but child is non-positioned, the positioned parent acts as if it creates a stacking context for its non-positioned child, hence child is always top of the parent.