Please picture the following HTML page in your head:
<html>
<body>
<h1>Hello World</h1>
</body>
</html>
You open it in the browser. What is the color of the page?
You could argue that this is a trick question because white is not really a color, but the page is not white anyway: it's transparent. Sure, the browser is white, but the page displayed inside the browser is transparent.
Prove me that the page is not white because it is kind of white I must say
Philosopher mode on :
So what is a page?
Two elements must be considered here:
- The
body
element - The
html
element
If we want the page to have a yellow background, we can put a background-color
on the body:
body {
background-color: yellow;
}
From this example, we can assume that the body fills the whole viewport, because everything is yellow now.
That is not true. Let's add a border to the body:
You can see that, actually, the body only uses the space it needs to present the content "Hello World".
So why all the yellow?
Oh, you'll have to ask the w3c:
The background of the root element becomes the background of the canvas and its background painting area extends to cover the entire canvas.
Human translation: you put a background on the body. The browser will use that as a background for the canvas.
The canvas, you say?
The document canvas is the infinite surface over which the document is rendered.
So that's pretty big.
The notion of canvas is absent from most CSS courses (including mine, I must admit), although it's a very important part of the browser. As we've seen, based on the body
, it provides a background for the whole viewport.
With that new information let's update our mental model of the page, from top to bottom:
- The
body
element - The
html
element - The canvas
For a long time I thought that the canvas was all yellow because the body
was the canvas. Nope: the canvas just uses information from the body
, and the canvas can be much bigger than the body
itself.
It's interesting to note that even though we set the body to be yellow, it is actually transparent. As the w3c puts it:
The background of the root element becomes the background of the canvas [...] The root element does not paint this background again, i.e., the used value of its background is transparent.
It's useless for the browser to paint the body
, which has the same color as the canvas : that's why it's treated as transparent.
In other words: when you set a background color on the body
, you are actually styling the canvas (which cannot be styled directly in CSS). The canvas "steals" the value from the body
.
Beyond the body
Philosopher mode on :
So what is the body?
According to the w3c, the body is
where the content appears: text, images, colors, graphics, etc.
If the body
is the content, it seems safe to say that what is outside of the body
is not the content.
So surely setting a background-color
on the html
element won't have any effect, because it's not part of the content?
Stop and think about it: what would our page look like with this CSS?
html {
background-color: green;
}
body {
background-color: yellow;
}
What is the color of the page now? Is it yellow, is it green, is it both? Of course it's both.
What can we see?
- The yellow is now limited to the
body
. - The
html
element seems to fill the whole viewport.
Wrong! Once again we are fooled.
But it does fill the viewport! The whole page is green!
I know. But let's add borders to the html
element to see what happens:
At this point it's worth noting that the browser has no problems applying styles (such as borders) outside of the body
. But let's continue.
So actually, the html
behaves just like the body
: it only takes the space needed to host its content: the body
and its 8px
margin coming from the browser default styles.
So WHY the green everywhere?
Same answer from the w3c :
The background of the root element becomes the background of the canvas.
We also learn that the root element can be the body
or the html
:
It is recommended that authors of HTML documents specify the canvas background for the BODY element rather than the HTML element.
Although the w3c recommends that we don't use the html
element for that, we just did, and that's where the canvas green color is taken from.
Like in the first example, the html
is treated as transparent : its green is "stolen" by the canvas.
We now have the full algorithm that the browser uses to choose the color of the canvas:
if (the html has a background-color) {
use it to paint the canvas
}
else if (the body has a background-color) {
use it to paint the canvas
}
else {
the canvas stays transparent
}
Well, that's one mystery solved I guess, and that's not that strange. You could say this is quite smart that we don't have to give explicit dimensions to the root element in order to have a background color filling the viewport.
Why does this matter? What about the white VS transparent thing?
Understanding that there is a difference between white and transparent, even if both situations look identical, is key to figure out some CSS mysteries.
Let's have fun with mix-blend-mode
. This CSS property allows us to define how an element should blend with its parent. Sometimes referred as "Photoshop in the browser". Exageration or not, the possibilities are amazing.
We begin with a simple example: the h1
will be green, and we want to change its appearance with mix-blend-mode: difference
.
h1 {
color: green;
mix-blend-mode: difference;
}
The difference
value means that the color of the text will be the difference between its original color (green) and the color of the background.
The difference between green and white is pink. So hopefully, our title will be pink.
It is not, I repeat, it is not pink.
But it should blend! The background is white!
No, it isn't. It's transparent.
The difference between green and transparent is green, hence the color of the title, unchanged.
Let's recap:
- The
body
is transparent (default value ofbackground-color
) - The
html
is transparent (default value ofbackground-color
) - The canvas is transparent (no value provided by
html
norbody
)
So our poor title has nothing to blend with.
The fix is easy: just put a background-color
on the body
!
body {
background-color: white;
}
It now works!
Let's recap again:
- The
body
istransparent
(white
set in the CSS, but "stolen" by the canvas) - The
html
is transparent (default value ofbackground-color
) - The canvas is white (the value is taken from the
body
)
And so our green title blends with the canvas and turns pink. This title could of course be an image, a video, anything. The body
(or any element containing our target) must have a background (you could also set a background to the html
to achieve that, but that's non-standard).
Our journey is coming to an end, but there is one last question…
What is the color of a blank canvas?
Our mental model of the page is this:
- The
body
element - The
html
element - The canvas
According to what we learned, if the body
and the html
are transparent, the canvas will be transparent too.
But how can the bottom layer be transparent? If this was the case, we would see the desktop and the other windows through the browser! You're nuts!
Hear me out. What if there is another layer, actually white, below the canvas?
Once again, the w3c gives the answer:
If the canvas background is not opaque, what shows through is UA-dependent.
Human translation : there is something behind the canvas. You can see it if the canvas is transparent. What you see depends on the browser.
On every browser I can think of, this bottom layer is white. But theoretically, it could also show a picture of a horse eating an pineapple pizza. What a strange web that would be.
Anyway, this led me to think: is there any way to actually see the difference between a white and a transparent canvas? Can we have proof that the default canvas is transparent? Just asking for a weird friend.
The iframe clue
Let's go back to a very simple CSS:
html, body {
border: 3px dashed black;
}
Our page looks like that:
Let's include that page in another one with an iframe
tag:
<iframe src="..." width="100%" height="300px"></iframe>
Here's what we get :
So, the question is : does the iframe
have a transparent or white canvas?
We can answer this question by setting a background-color on the parent page.
body {
background-color: lightblue;
}
As you can see, the iframe is transparent. body
, html
, and canvas. We can see the parent page through it.
Does it really prove that the canvas is transparent? Maybe iframes just don't have a canvas?
That's a fair question. To answer that, let's put a white background on the iframe
's body
tag:
body {
background-color: white;
}
Here's what we get:
If the iframe didn't have a canvas, the area outside its body
wouldn't be filled. But thanks to the canvas mechanism, the background color of the body
can be used to cover the whole iframe
viewport.
And that's how we can see that on any page, the default canvas is not white but transparent.
So what you see when you open a blank page is not a white canvas. It's just the "bottom" of the browser, the background of the software, outside of CSS land, not meant to interact with anything.
Hence our (final?) mental model of what we see:
- The
body
element (transparent by default) - The
html
element (transparent by default) - The canvas (depends on the
html
andbody
, so transparent by default) - The inaccessible software foundations (often white)
Oh, and I tried to represent it visually :
That was a nice trip. And yes, I'm fun at parties. If you have any input about all of this, please leave a comment!
CSS is a lot about what you see, but also a lot about what you don't.
Top comments (34)
I remember in the ’90s when most browsers’ background color was grey. IE was the only one that has a white browser background by default. Others followed suit.
In fact you can change the browser background color in Firefox in
about:config
by settingbrowser.display.background_color
. I have set this to grey to check if I haven’t accidentally forgotten to addbackground:white
to a page that should have a white background.I remember when they wanted to fix the weird special-casing of the
body
tag (which is NOT the root element but can upwards-„inherit“ its color to thehtml
element, which is root) in XHTML. Still today, pages sent with the correct XHTML mime type (application/xhtml+xml
) will not show this behaviour. Setting a background on thebody
tag there won’t make it magically stretch to the canvas.Sadly, true XHTML never saw any real adoption…
That is super-interesting, thank you so much for this comment.
Would you be ok with me writing a small bonus article and quoting your comment ?
I think more people need to know about this grey background tip.
Very interesting details about xhtml too, thanks!
Sure, by all means, bonus away…
xhtml
... wow, haven't seen a mention of that in a whileNetscape definitely had a grey "blank page":
Indeed, I'm currently writing about this! (not the main subject, but part of it)
It's a small Hello World after all..... nice article
Great Article!
so if we leave our html/body without any background, and the browser changes to dark mode, would that change the browser background?
Thanks!
The answer seems compicated.
I just tried the #enable-force-dark flag to force dark mode on every site on Chrome.
It looks like it doesn't try to replace black background with white : it considers white to be black ! (see screenshot)
So background-color: white | transparent | black | none has the same effect : you see black. I think that yes, the browser's background changes, but that's really a wild guess.
Maybe something to explore in another article ;)
This was a really well-written article! I think we should petition Google and Mozilla to let us customize our default browser backgrounds. I personally would love it to actually be transparent and show me my desktop through the browser window
I learned that this is possible in Electron by setting the background color of the body to "transparent" !
But nothing like that in the browser indeed
Thank you! It's a very interesting article!
You're a genius writer with your dev stuff, this made me wonder, are a member of the w3c or you sat down and figured this shit out yourself? You're great man. You've added greatly to my knowledge today
Thank you very much, I'm so glad you liked it!
I'm just a front-end teacher ;) One of my student struggled with this mix-blend-mode thing, so I sat down and tried to get to the bottom of this with many tests. Had to read a lot of w3c documentation ^^
Actually I started writing another post on the same subject, because there is too much to say!
Small correction: The “root element” is the
<html>
element, not the<body>
element.Small shortcut, I agree. The
<html>
is of course the root, but the browser uses the<body>
rules as if they were set on the<html>
."The used values of that BODY element’s background properties are their initial values, and the propagated values are treated as if they were specified on the root element."
Iframe has
allowtransparency
-- stackoverflow.com/questions/374070... so I always know it is transparent.Thanks, I didn't know about that !
But I could not produce an example in which allowtransparency had any impact. The iframe is transparent by default.
Is it for specific browsers/environments ?
Those wonderful thing we can learn about CSS 😍 thank you for sharing!
Good stuff. Most of this I knew, but the point about the blend-modes had passed me by. Thanks for the explanation.