1

Seems like I just found a bug or something. Usually when an element has a pseudo-element and I want it to show behind its parent I use z-index:-1. This works fine if the element has position relative or absolute but on position fixed something weird happens: the pseudo-element comes between the background and the text of the element like this:

div {width:200px;height:100px;position:fixed;background:black;display:block;}
div::after {content:"";position:absolute;top:0;width:100%;height:100%;background:red;z-index:-1;display:block;}
<div>
 example
</div>

Can this be fixed so the pseudo-element goes completely behind the parent as it does with the other positions?

Thank you.

gobler
  • 95
  • 1
  • 6

1 Answers1

5

The behavior your are experiencing is due to stacking contexts in CSS:

A stacking context is formed, anywhere in the document, by any element in the following scenarios:

  • […]
  • Element with a position value absolute or relative and z-index value other than auto.
  • Element with a position value fixed […]

So when you use position: fixed on the parent, it becomes a new stacking context, whereas when you use position: absolute or position: relative without a z-index, it is not a new stacking context, which is why you see this discrepancy in behavior.

When the parent element is a stacking context it becomes a "container" for position stacking. The text or other elements inside it are by default at the stacking position 0 but the pseudo element in your example has z-index of -1 so it goes behind the text. It does not go behind the parent because the parent itself is the container. It is like you have all these elements in a box and elements can't go outside the the box.

So to have the pseudo element be behind its stacking context parent, we can use a 3D transform to translate the pseudo element behind the plane of the parent. We add transform-style: preserve-3d so "that the children of the element should be positioned in the 3D-space" and then we can add transform: translateZ(-1px) to push the child element behind:

div {
  width:200px;
  height:100px;
  position:fixed;
  background:black;
  display:block;
  transform-style: preserve-3d;
}
div::after {
  content:"";
  position:absolute;
  top:0;
  width:100%;
  height:100%;
  background:red;
  z-index: -1;
  display:block;
  transform: translateZ(-1px);
}
<div>
 example
</div>
Wongjn
  • 8,544
  • 2
  • 8
  • 24