Every HTML page has a stacking context at the root element (html
tag).
In the following example the html
tag is the (only) stacking context
html {
background-color: gray;
}
body {
background: #222;
color: white;
box-sizing: border-box;
}
.box {
width: 200px;
height: 200px;
background-color: blue;
position: relative;
}
.box:before {
content: "";
background-color: tomato;
position: absolute;
z-index: -1;
inset: 0;
margin: -5px;
}
<h1>Header</h1>
<div class="box"></div>
The pseudo element (tomato color) is drawn behind the body background (#222) because it has a z-index
< 0
If we remove the html
tag background color:
body {
background: #222;
color: white;
box-sizing: border-box;
}
.box {
width: 200px;
height: 200px;
background-color: blue;
position: relative;
}
.box:before {
content: "";
background-color: tomato;
position: absolute;
z-index: -1;
inset: 0;
margin: -5px;
}
<h1>Header</h1>
<div class="box"></div>
Now the pseudo element (tomato color) is drawn after the body background (#222). That means that the body
tag now creates a stacking context.
There are a few rules that determine if an element creates a stacking context. None of the rules explain why the body
tag is now the root of a stacking context.
A similar question on SO explains, from the specs, that the canvas uses the body
background color/image if the html
tag has none. This is possibly to match the early days of HTML when this info was set with the bgcolor
and background
attributes of the body
tag.
The question is: which part of the CSS specification is the reason of the body
tag creating a stacking context depended on the html background color?
If we add a border to the body element, we can see that it is not in fact creating a stacking context. If the body element did create a stacking context, then the box would be painted over the border. But that doesn't happen: the border is painted over the box.
body {
background: #222;
color: white;
box-sizing: border-box;
border:3px solid yellow;
}
.box {
width: 200px;
height: 200px;
background-color: blue;
position: relative;
}
.box:before {
content: "";
background-color: tomato;
position: absolute;
z-index: -1;
inset: 0;
margin: -5px;
}
<h1>Header</h1>
<div class="box"></div>
In contrast, if we force the body to create a stacking context - in the example below I've used scale: 1
to do that - we can see that now the box is indeed painted over the body's border.
body {
background: #222;
color: white;
box-sizing: border-box;
border:3px solid yellow;
scale: 1;
}
.box {
width: 200px;
height: 200px;
background-color: blue;
position: relative;
}
.box:before {
content: "";
background-color: tomato;
position: absolute;
z-index: -1;
inset: 0;
margin: -5px;
}
<h1>Header</h1>
<div class="box"></div>
So we can be sure that the propagation of the body background to the canvas is not causing the body to create a stacking context - it's merely having a similar outcome when the body has no border.