Please see this very simple snippet to illustrate my question below:
#container {
position: relative;
padding: 20px;
border: 2px solid gray;
}
#back {
position: absolute;
top: 0;
bottom: 50%;
left: 0;
right: 0;
background-color: #bbb;
}
<div class="col-sm-12" id="container">
<div id="back"></div>
<h1>Some Text</h1>
</div>
The h1
tag is after the back
element, in the HTML code.
As I don't change its position
property, it must be static
.
And, as far as I know, static
elements are positioned according to the flow of the page.
So… Why is the absolute-positioned div
is shown above its sibling h1
?
I am expecting to see it behind the h1
since it comes first.
Note that I know how to correct this behaviour, I'm just asking why!
Snippet with correction:
#container {
position: relative;
padding: 20px;
border: 2px solid gray;
}
#back {
position: absolute;
top: 0;
bottom: 50%;
left: 0;
right: 0;
background-color: #bbb;
}
/* Adding the below corrects this behaviour */
h1 {
position: relative;
}
<div class="col-sm-12" id="container">
<div id="back"></div>
<h1>Some Text</h1>
</div>
… And why using position: relative
on the h1
corrects this behaviour?
This is how the painting order works. As described here you have the following order:
- For all its in-flow, non-positioned, block-level descendants in tree order: If the element is a block, list-item, or other block
equivalent:
In this step you will print the background and border of the h1
element
- Otherwise: first for the element, then for all its in-flow, non-positioned, block-level descendants in tree order:
In this complex step you will print the content of the h1
element
All positioned, opacity or transform descendants, in tree order that fall into the following categories:
- All positioned descendants with 'z-index: auto'
And in this step you will print the positioned element #back
; thus it will be on the top of h1
even if in the DOM it's before.
In other words, we first consider the in-flow elements then the postioned ones. Of course, changing z-index
and/or other properties will affect the order because more steps can be consider.
For example adding a negative z-index
to #back
will trigger this rule:
- Stacking contexts formed by positioned descendants with negative z-indices (excluding 0) in z-index order (most negative first) then
tree order.
This will make the #back
to be behind since h1
is printed later in the step (4) and (7).
Adding position:relative
(or absolute
or fixed
) to h1
will make it a positioned element so like #back
it will trigger the (8) and in this case the tree order will decide.
You may also notice that both background and content are printed in 2 different steps and this may also lead to some non intuitive painting behavior.
Try following. Add style for h1
as follows
#container {
position: relative;
padding: 20px;
border: 2px solid gray;
}
#back {
position: absolute;
top: 0;
bottom: 50%;
left: 0;
right: 0;
background-color: #bbb;
}
#container h1 {
position : relative;
z-index: 1;
}
<div class="col-sm-12" id="container">
<div id="back"></div>
<h1>Some Text</h1>
</div>
static elements
do not have a z-index
, however, the others default to 0
that is why it stays at the bottom most layer of html and the non-static element covers it. If you wish to show them above, set the position
of static elements to relative
and give any positive z-index value
.
The top
, right
, bottom
, left
, and z-index
properties have no effect for position: static
which is the default value for elements, in your case which h1
tag is. When position is set to relative it creates a new stacking context when the value of z-index is other than auto.
For more read on stacking context:
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context