Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 837
Peter Olson Avatar asked Aug 20 '15 03:08

Peter Olson


People also ask

Why does my Z Index not work?

You set z-index on a static element By default, every element has a position of static. z-index only works on positioned elements (relative, absolute, fixed, sticky) so if you set a z-index on an element with a static position, it won't work.

Does Z index only work with absolute positioning?

Note: z-index only works on positioned elements (position: absolute, position: relative, position: fixed, or position: sticky) and flex items (elements that are direct children of display:flex elements).

Will Z Index work for an element without position?

In order for z-index to have any effect at all, it needs to be applied to a positioned element, that means, an element with position relative , absolute , fixed , or sticky . If you don't apply a z-index , the elements will be stacked in the order they are written in the HTML. Check this example: HTML.

What can the Z Index property be used for?

The z-index CSS property sets the z-order of a positioned element and its descendants or flex items. Overlapping elements with a larger z-index cover those with a smaller one.


3 Answers

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

like image 130
Shaunak Avatar answered Nov 05 '22 21:11

Shaunak


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>
like image 36
Alohci Avatar answered Nov 05 '22 20:11

Alohci


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

like image 31
Michael Benjamin Avatar answered Nov 05 '22 21:11

Michael Benjamin