When statically positioned, the ::before pseudo-element stacks (z-index) before the child's content, but after the child's background. Can anyone explain why or even how this is happening or if this is an issue that all major browsers have?
<style>
div { background-color:yellow; width:400px; }
div::before { background-color:red; content:"div::before"; }
div::after { background-color:green; content:"div::after"; }
div p { background-color:blue; color:white; margin:-15px 0; padding:0; }
</style>
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sed tellus sed tellus sodales hendrerit tristique et elit.</p>
</div>
http://jsfiddle.net/funkyscript/ALrgf/
To position a pseudo-element below its parent, you have to create a new stacking context to change the default stacking order. Positioning the pseudo-element (absolute or relative) and assigning a z-index value other than “auto” creates a new stacking context.
The ::before pseudo-element can be used to insert some content before the content of an element.
Definition and UsageThe ::before selector inserts something before the content of each selected element(s). Use the content property to specify the content to insert. Use the ::after selector to insert something after the content.
The contents of the div
, which include the two pseudo-elements and the p
element, participate in the same stacking context (relative to the div
). This is because, as you note, all three of them are statically-positioned; in other words, not positioned at all. (Yes, these elements do stack along the z-axis while in flow; you simply cannot manipulate their stack levels using z-index
because they're not positioned.)
Here's a summary1 of the order in which the various parts are drawn, bold emphases where relevant to your question:
Each box belongs to one stacking context. Each positioned box in a given stacking context has an integer stack level, which is its position on the z-axis relative other stack levels within the same stacking context. Boxes with greater stack levels are always formatted in front of boxes with lower stack levels. Boxes may have negative stack levels. Boxes with the same stack level in a stacking context are stacked back-to-front according to document tree order.
Within each stacking context, the following layers are painted in back-to-front order:
- the background and borders of the element forming the stacking context.
- the child stacking contexts with negative stack levels (most negative first).
- the in-flow, non-inline-level, non-positioned descendants.
- the non-positioned floats.
- the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
- the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
- the child stacking contexts with positive stack levels (least positive first).
Since div::before
is inserted before the content of the div
, and div::after
is inserted after it, when they display inline in a static position they'll naturally follow this rule, even if sandwiching a block element (the ordering takes both block boxes and inline boxes into account).
Notice that, for obvious reasons, backgrounds are usually painted first, with the content overlaying them:
The p
element, as a block-level element, has a background that's painted first (#3).
The inline-level pseudo-elements are then drawn with their backgrounds over the p
background (#5). In the formatting model, they are siblings of the p
element, so they all participate in the stacking context of the div
and not that of the p
.
The div::before
pseudo-element (both its content and background) appears behind the p
text because it comes before the p
in the visual tree.
The div::after
pseudo-element (both its content and background) appears in front of the p
text because it comes after the p
in the visual tree.
As indicated in my comment, if you make the pseudo-elements display as blocks, the background of the div::before
will hide behind that of the p
element, but not the text; instead, the text of the div::before
will be positioned between the background and the text of the p
element. Also notice that the background of the div::after
is painted in front of that of the p
, while the content is painted frontmost. Again, this has to do with backgrounds being painted before, or behind, content in relation to the rules above.
1A much more detailed description can be found in Appendix E of the spec.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With