Search code examples
htmlcssz-indexdocument-body

Why doesn't the z-index style apply to the <body> element?


The z-index style allows you to control what order boxes are painted in. For example, you can make a child element be painted below its parent element:

#parent {
  background: rgba(33, 33, 33, 0.7);
}
#child {
  width: 100px;
  height: 100px;
  background: yellow;
  position: relative;
  z-index: -1;
}
<div id="parent"><div id="child"></div></div> 

However, when the parent element is the <body> tag, this no longer behaves as expected:

body {
  background: rgba(33, 33, 33, 0.7);
}
#child {
  width: 100px;
  height: 100px;
  background: yellow;
  position: relative;
  z-index: -1;
}
<body>
  <div id="child"></div>
</body>

The CSS specification §9.9.1 states (emphasis mine):

The root element forms the root stacking context. Other stacking contexts are generated by any positioned element (including relatively positioned elements) having a computed value of 'z-index' other than 'auto'. Stacking contexts are not necessarily related to containing blocks. In future levels of CSS, other properties may introduce stacking contexts, for example 'opacity' [CSS3COLOR].

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

If <body> were the root element, then this behavior would make sense, since that would mean that the <body> element is always painted first no matter what.

However, in an HTML document, <html> is the root element. Given that, why can't we place an element under <body> with the z-index style?


(This question was motivated by a similar question on the Russian Stack Overflow site.)


Solution

  • The issue here is that if the html element doesn't have a background specified, the canvas adopts the background of the body element, and that gets painted first. CSS 2.1 says:

    For documents whose root element is an HTML "HTML" element or an XHTML "html" element that has computed values of 'transparent' for 'background-color' and 'none' for 'background-image', user agents must instead use the computed value of the background properties from that element's first HTML "BODY" element or XHTML "body" element child when painting backgrounds for the canvas, and must not paint a background for that child element.

    See what happens when the html element is given a background:

    html { 
      background-color: white;
    }
    
    body {
      background: rgba(33, 33, 33, 0.7);
    }
    #child {
      width: 100px;
      height: 100px;
      background: yellow;
      position: relative;
      z-index: -1;
    }
    <body>
      <div id="child"></div>
    </body>