2

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?

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
Takit Isy
  • 9,688
  • 3
  • 23
  • 47
  • 4
    When you position an element absolutely, you remove it from the flow of the DOM. There's a helpful [explanation here](https://maymay.net/blog/2004/11/20/centering-absolute-positioning-and-document-flow/) – Lewis Jun 14 '18 at 07:56
  • @Lewis Does it mean that using `position: relative` like in my 2nd snippet also removes the `h1` from the flow? – Takit Isy Jun 14 '18 at 08:02
  • No. I'm not 100% sure of the mechanics, but I think when you add `position:relative` to an element, it gains the ability to move along the z-index (try z-indexing an element without a position, it'll do nothing). It is established with a default value of `:auto`. More good info in this SO question [here](https://stackoverflow.com/questions/8986071/how-to-use-z-index-with-relative-positioning?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa) (Look at Quentin's answer specifically). – Lewis Jun 14 '18 at 08:04
  • @Lewis it has nothing to do with z-index, but this is the logical paiting order – Temani Afif Jun 14 '18 at 10:18
  • @TemaniAfif The logical painting order when considering positioned elements, yes - which for all intents and purposes, adding `position: relative` to an element gives it z-index: 0, no? (Genuine question) – Lewis Jun 14 '18 at 10:36
  • 1
    @Lewis no, am talking about the logical painting order considering all the elements (as described in my answer) and z-index has nothing to do here ... and it will not be 0 by default but it's `auto` (it may be the same but not exactly) – Temani Afif Jun 14 '18 at 10:38
  • Thanks! Sorry, 0 for all intents and purposes. I did mean to refer to `:auto` as I mentioned before though. Interesting stuff, nice answer. – Lewis Jun 14 '18 at 10:39
  • 1
    @Lewis read the step 8 closely and you will see the difference between auto and 0 in z-index. 0 will create a stacking context BUT auto will not and there is a big difference here ;) – Temani Afif Jun 14 '18 at 10:40
  • @dippas I have to disagree that this is a duplicate. The accepted answer says "position: relative […] is nothing but same as static"… But adding `position: relative` prevents my issue in my 2nd snippet! So it's not the same at all! – Takit Isy Jun 14 '18 at 15:22
  • I also totally disagree with the duplicate .. it has nothing to do with this question. it's not about how different positons works but how the painting order works .. reponned the question – Temani Afif Jun 14 '18 at 15:35
  • Thanks @TemaniAfif, I feel less stupid. :) – Takit Isy Jun 14 '18 at 16:10

3 Answers3

5

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.

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
-1

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.

Nikhil Aggarwal
  • 28,197
  • 4
  • 43
  • 59
-1

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

Kushtrim
  • 1,899
  • 6
  • 14
  • I know about the *no effect for position: static*. Note that I didn't use any of the properties you mentioned on my `h1`. – Takit Isy Jun 14 '18 at 08:28
  • Your `h1` element by default is `position: static` where `z-index` does not work. When you use `position: relative` for `h1` a new stacking context is created in which default `z-index` is set. – Kushtrim Jun 14 '18 at 08:31