Why using absolute position causes the div to be o

2020-01-29 21:20发布

问题:

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?

回答1:

This is how the painting order works. As described here you have the following order:

  1. 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

  1. 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

  1. All positioned, opacity or transform descendants, in tree order that fall into the following categories:

    1. 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:

  1. 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.



回答2:

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.



回答3:

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