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

5

6

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

Interleave answered 20/8, 2015 at 3:50 Comment(1)
just like how overflow hidden doesnt work on bodyUncommitted
L
6

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>
Lording answered 20/8, 2015 at 6:54 Comment(3)
This makes the most sense to me of anything so far, is there a reason why it was deleted earlier?Interleave
I deleted it while I double-checked my facts.Lording
Thanks for this, I hope you don't mind if I borrow the gist of this answer to answer the related question on the Russian site.Interleave
S
9

<body> tag's default positioning is static. And by definition static positioning means ignore all positioning instructions.

In other words because z-index property does not apply to elements that have position:static, it does not apply to body as it's position defaults to static

Here's a good discussion on why z-index does not work on position:static

Update: So why doesn't it work with body { position:relative } ?

Because body get's a stacking context. Now with z-index, a element can only go behind or forward relative to its siblings but never behind its parent. Because body is a parent element, setting negative z-index on it's child does not take it behind body.

Silicate answered 20/8, 2015 at 4:17 Comment(3)
If you change Body position to relative its still the sameMeath
In that case, why doesn't it work when you add body {position: relative;}?Interleave
@PeterOlson great question. Please check my update on the answer that tries to answer this.Silicate
L
6

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>
Lording answered 20/8, 2015 at 6:54 Comment(3)
This makes the most sense to me of anything so far, is there a reason why it was deleted earlier?Interleave
I deleted it while I double-checked my facts.Lording
Thanks for this, I hope you don't mind if I borrow the gist of this answer to answer the related question on the Russian site.Interleave
S
1

Hard to find official, or even authoritative, documentation on this issue, probably because it's not a common real-life scenario, but the issue has been discussed before by Ian Hickson and Tantek Celik, the editors of the CSS Specification.

Below are some parts of a thread from a W3C mailing list in which spec writers discuss the behavior of z-index in relation to the body element.

The essence of the discussion is this:

  • The browser is right to ignore z-index on non-positioned elements (like body), because z-index applies only to positioned elements

  • z-indexing of an element is relative only to sibling elements, and not to parent elements, due to the creation of stacking contexts

    ... a child box cannot circumvent the z-order of its parent. it can place itself behind or in front of any of its siblings, but it cannot place itself behind it's parent box. it can place itself in such a way that it is first child rendered before any other child ....

  • There's also an interesting note about the behavior of z-index with position: fixed on the body element, but it doesn't look like it was implemented.


Tantek Celik:

I've got a question regarding the z-index property: Why can I still see elements which I've put behind the BODY element (see example below)?

Because your browser has a bug or doesn't support z-index.

Or the browser doesn't have a bug and is properly ignoring z-index on non-positioned elements.

<BODY STYLE="z-index: 0; background-color: #456789;">
<P STYLE="z-index: -1; color: #fedcba;">This is a test showing a text that shouldn't be visible as it lies behind the body element <EM>("z-index" property equals "-1").</EM>
</BODY>

In the example given, both elements which have a z-index do not have their position property set, and since according to:

http://www.w3.org/TR/REC-CSS2/visuren.html#z-index

the z-index property "Applies to: positioned elements", the settings on the z-index property are ignored.

Tantek

response from spec writer:

hi,

(Tantek: i do agree with you that the spec says z-index is only for positioned elements, but as Ian says, i don't see why it cannot be applied for static boxes which overlap due to negative margins.)

look at the following markup:

<body style="z-index=0; background-color=green;">
<p style="z-index=-1; position: relative; top: 50; left: 20"> hello!! </p>
<p> world!! </p>
</body>

P is a child of BODY, and according the CSS2 spec (my reading, anyway :) z-indexing of an element is relative only to sibling elements, and not to parent elements. this has to do with the creation of a z-index contexts.

so the box for 'hello!!' would show up behind the box for 'world!!' but NOT behind the box for BODY because BODY contains both P element boxes.

!!! please correct if i'm wrong on this, because if i am, i have to redo my renderer so that it does not respect hierarchical boundaries, which is NOT a happy situation. !!!

the original intent of this thread (the question) can be attained by making the z-index=-1 box a position: fixed box (though the positioning properties would be complex.) this would work because fixed boxes break out of the hierarchy where they are found and levitate to the viewport box, essentially becoming a sibling to the BODY box.

-- ranjit

spec writer:

please,

pardon my use of implementation specific terms.

you are correct about the HTML assumption. but my point remains valid, even if we look at the hierarchy of the document/box structure regardless of markup.

currently, in my implementation, the following implicit rule is dictated by the hierarchical structure of the boxes generated by parsing a hierarchical document structure (XML, HTML, ...)

RULE: a child box cannot circumvent the z-order of its parent. it can place itself behind or in front of any of its siblings, but it cannot place itself behind it's parent box. it can place itself in such a way that it is first child rendered before any other child, ....

i see this rule implied by the CSS2 spec as well, in the section where there is talk of z-order contexts and so on.

as i see it, z-order values for a CHILD boxes are valid within the parent z-order context. this can be illustrated with absolute positioned boxes containing absolute positioned boxes where a child absolute boxes have a z-ordering that cannot violate the z-ordering of the parent absolute boxes.

again, let me say: if i have misunderstood something in the spec, let me know, for if the above rule is invalid, then it seems to me the notion of hierarchy is not preserved for non-fixed boxes.

regards,

-- ranjit

http://lists.w3.org/Archives/Public/www-style/1999Aug/0131.html

Salbu answered 20/8, 2015 at 4:48 Comment(1)
wow, you're a legend! how did you find this!Scaramouch
A
0

The <body> tag is defaulted to stay on the bottom of the stack. It simply cannot be set as it will always be the lowest possible value.

Source: Adobe Forums

Affecting answered 20/8, 2015 at 4:9 Comment(0)
M
0

Well, there isn't much documentation about this.

But the <body> tag can't have any siblings, so why would ever be a need to change its z-index?

Is it even considered a 'positioned' element?

You may play with its child elements z-index as you wish and get desired results in any situation, there is no need to over-complicate html with css styles with no reason at all

Meath answered 20/8, 2015 at 4:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.