Why the content is not covered by the background of an overlapping element?

WARNING: Reading the following information can affect your mental health.

The painting order for the descendants of an element generating a stacking context (see the z-index property) is:

  1. If the element is a root element:
    1. background color of element over the entire canvas.
    2. background image of element, over the entire canvas, anchored at the origin that would be used if it was painted for the root element.
  2. If the element is
    • a block, list-item, or other block equivalent:
      1. background color of element unless it is the root element.
      2. background image of element unless it is the root element.
      3. column rule of the element.
      4. border of element.
    • Otherwise, if the element is a block-level table:
      1. table backgrounds (color then image) unless it is the root element.
      2. column group backgrounds (color then image).
      3. column backgrounds (color then image).
      4. row group backgrounds (color then image).
      5. row backgrounds (color then image).
      6. cell backgrounds (color then image).
      7. cell column rule for multi-column.
      8. all table borders (in tree order for separated borders).
  3. Stacking contexts formed by positioned descendants with negative z-indices (excluding 0) in z-index order (most negative first) then
    tree order.
  4. 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:
      1. background color of element.
      2. background image of element.
      3. column rule of the element.
      4. border of element.
    • Otherwise, the element is a table:
      1. table backgrounds (color then image).
      2. column group backgrounds (color then image).
      3. column backgrounds (color then image).
      4. row group backgrounds (color then image).
      5. row backgrounds (color then image).
      6. cell backgrounds (color then image).
      7. cell column rule (multi-column).
      8. all table borders (in tree order for separated borders).
  5. All non-positioned floating descendants, in tree order. For each one of these, treat the element as if it created a new stacking
    context, but any positioned descendants and descendants which actually
    create a new stacking context are considered part of the parent
    stacking context, not this new one.
  6. If the element is an inline element that generates a stacking context, then:
    1. For each line box that the element is in:
      1. Jump to 7.2.1 for the box(es) of the element in that line box (in tree order).
  7. Otherwise: first for the element, then for all its in-flow, non-positioned, block-level descendants in tree order:

    1. If the element is a block-level replaced element, then: the replaced content, atomically.
    2. Otherwise, for each line box of that element:

      1. For each box that is a child of that element, in that line box, in tree order:

        1. background color of element.
        2. background image of element.
        3. column rule of the element.
        4. border of element.
        5. For inline elements:
          1. For all the elements in-flow, non-positioned, inline-level children that are in this line box, and all runs of text inside the
            element that is on this line box, in tree order:

            1. If this is a run of text, then:
              1. any underlining affecting the text of the element, in tree order of the elements applying the underlining (such that the deepest
                element’s underlining, if any, is painted topmost and the root
                element’s underlining, if any, is drawn bottommost).
              2. any overlining affecting the text of the element, in tree order of the elements applying the overlining (such that the deepest
                element’s overlining, if any, is painted topmost and the root
                element’s overlining, if any, is drawn bottommost).
              3. the text
              4. any line-through affecting the text of the element, in tree order of the elements applying the line-through (such that the deepest
                element’s line-through, if any, is painted topmost and the root
                element’s line-through, if any, is drawn bottommost).
            2. Otherwise, jump to 7.2.1 for that element
        6. For inline-block and inline-table elements:
          1. For each one of these, treat the element as if it created a new stacking context, but any positioned descendants and descendants
            which actually create a new stacking context are considered part of
            the parent stacking context, not this new one.
        7. For inline-level replaced elements:
          1. the replaced content, atomically.
        8. Optionally, the outline of the element (see 10 below).

        Note, some of the boxes may have been generated by line splitting or the Unicode bidirectional algorithm.

    3. Optionally, if the element is block-level, the outline of the element (see 10 below).

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

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

    2. All opacity descendants with opacity less than 1, in tree order, create a stacking context generated atomically.

    3. All transform descendants with transform other than none, in tree order, create a stacking context generated atomically.
  9. Stacking contexts formed by positioned descendants with z-indices greater than or equal to 1 in z-index order (smallest first) then tree
    order.

Now seriously, refer to the w3c paint order documentation

In point 4.1, the background of children is painted

In point 4.4, the border of children is painted.

When point 4 is finished, all background and border of your snippet have been painted

Now, in point 7.2.1.5.1.1.3, the text of the children is painted.

This is the behaviour that you are seeing.

Notice also that is easy to change this behaviour. We can activate point 8.2, (setting opacity) and it will paint like you may have expected:

body {
  margin: 0;
  background: pink;
  color: #fff;
}

.box {
  margin-top: 20px;
  background: red;
}

.bottom {
  text-align: right;
  background: green;
  animation: animate 2s infinite alternate linear;
  opacity: 0.9999;
}

@keyframes animate {
  from {
    margin-top: 10px;
  }
  to {
    margin-top: -40px;
  }
}
<div class="box">
  some content
</div>
<div class="bottom">
  other content
</div>

Another snippet, showing several point in the document:

Notice that all the border and background in step 4 are rendered after step 3, and before setp 5. But the text in step 4 is step 7, so is rendered after text in step 5

div {
  width: 200px;
  height: 100px;
  border: solid 10px;
  font-size: 40px;
}

.step3 {
  border-color: red;
  background-color: lightpink;
  z-index: -1;
  position: relative;
  margin-left: 10px;
}

.step41 {
  border-color: brown;
  background-color: yellow;
  margin-left: 30px;
  margin-top: -40px;
}

.step42 {
  border-color: blue;
  background-color: lightblue;
  margin-left: 50px;
  margin-top: -40px;
  color: red;
}

.step43 {
  border-color: green;
  background-color: lightgreen;
  margin-left: 160px;
  margin-top: -150px;
  color: crimson;
}

.step5 {
  float: left;
  background-color: white;
  margin-top: -30px;
}

div:hover {
  position: relative;
}
<div class="step3">Step 3 negative zindex</div>
<div class="step41">step4 In flow, number 1</div>
<div class="step42">In flow, number 2</div>
<div class="step43">In flow, number 3</div>
<div class="step5">step 5 float</div>

I don’t know if this counts as an use case : this more natural the initial behaviour the the one set by the elements positioning relative

div {
  width: 100px;
  height: 1.3em;
  border: solid 12px tomato;
  font-size: 18px;
}

div:hover {
  position: relative;
}
<div>a long stretch of text overflowing to the other div</div>
<div></div>

Leave a Comment