14

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/

Funkyscript
  • 153
  • 1
  • 1
  • 8
  • 1
    If you display both pseudo-elements as blocks, the `::before` background hides behind the `p` background: http://jsfiddle.net/BoltClock/cVzs8/1 Note that they display inline by default. – BoltClock Jun 18 '12 at 17:46
  • @BoltClock: that's weird, but, presentationally, it's interesting...is this a bug, or by design? (If you're even able, or in a position, to answer that.) – David Thomas Jun 18 '12 at 17:48
  • 1
    This as no effect, but shouldn't it have a single colon? `:before` and `:after`? – Kobi Jun 18 '12 at 17:48
  • 5
    @Kobi: The double-colon notation was introduced in CSS3 for pseudo-elements: http://www.w3.org/TR/selectors/#pseudo-elements – BoltClock Jun 18 '12 at 17:49
  • @BoltClock Thanks, that made me realize that it isn't so much an issue with the ::before, but with my understanding of static positioning. Using spans instead of pseudo-elements returns the same results. – Funkyscript Jun 18 '12 at 18:15
  • 1
    @David Thomas: You didn't think I was a member of the CSSWG, did you? :O (How I *wish*...) – BoltClock Aug 30 '12 at 16:47
  • @BoltClock: me too, then there'd be someone in that group whose reasoning, and explanations, I understand. Plus, how cool would that be!? – David Thomas Sep 04 '12 at 11:08

1 Answers1

31

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:

  1. the background and borders of the element forming the stacking context.
  2. the child stacking contexts with negative stack levels (most negative first).
  3. the in-flow, non-inline-level, non-positioned descendants.
  4. the non-positioned floats.
  5. the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
  6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
  7. 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:

  1. The p element, as a block-level element, has a background that's painted first (#3).

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

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

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


1 A much more detailed description can be found in Appendix E of the spec.

Community
  • 1
  • 1
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • 1
    This *almost* makes sense - but why is `:before` between the text and the background of the content? (OK, I guess that answers my question `:P`). Hey, this stuff is more complicated than I imagined... – Kobi Jun 18 '12 at 17:55
  • Using spans instead of pseudo-elements returns the same results. – Funkyscript Jun 18 '12 at 18:16
  • About what you said on bullet 2: from what I understand from the specs, both the pseudo-elements, the `p` and the text inside the `p` would be in the same stacking context (there's no `z-index`+`position` - or `opacity` - on the `p` creating a new one). Anyway, I've read your answer (and the specs, including [Appendix E](http://www.w3.org/TR/CSS21/zindex.html)) multiple times, trying to answer [this other question](http://stackoverflow.com/q/11127713/825789), but I'm failing to fully understand the cause of the problem. Maybe you could help? – bfavaretto Jun 20 '12 at 21:46