What is the color of a blank page?
Tags: html, css, webdev
Published: 2020-05-22 08:53:58

Please picture the following HTML page in your head:

```html
<html>
  <body>
    <h1>Hello World</h1>
  </body>
</html>
```

You open it in the browser. What is the color of the page?

![It's a CSS trap!](https://dev-to-uploads.s3.amazonaws.com/i/c2g4mq0kg4oxd5zmyu99.jpg)

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* :

<blockquote>So what is a page?</blockquote>

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:

```css
body {
  background-color: yellow;
}
```

{% codepen https://codepen.io/bcalou/pen/WNQggzY %}

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:

{% codepen https://codepen.io/bcalou/pen/PoPddaR %}

You can see that, actually, the body only uses the space it needs to present the content "Hello World".

<blockquote>So why all the yellow?</blockquote>

Oh, you'll have to ask the [w3c](https://www.w3.org/TR/css-backgrounds-3/#root-background):

<blockquote>The background of the root element becomes the background of the canvas and its background painting area extends to cover the entire canvas.</blockquote>

Human translation: you put a background on the body. The browser will use that as a background for the canvas.

The [canvas](https://www.w3.org/TR/css-backgrounds-3/#special-backgrounds), you say?

<blockquote>The document canvas is the infinite surface over which the document is rendered.</blockquote>

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` <i>was</i> 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](https://www.w3.org/TR/css-backgrounds-3/#root-background) puts it:

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

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* :

<blockquote>So what is the body?</blockquote>

According to the w3c, the body is

<blockquote>where the content appears: text, images, colors, graphics, etc.</blockquote>

If the `body` is the content, it seems safe to say that what is outside of the `body` is not the content.

![Yes, thank you for your input](https://dev-to-uploads.s3.amazonaws.com/i/efzd9izbaskuvxw97zgm.gif)

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?

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

{% codepen https://codepen.io/bcalou/pen/oNjPPNj %}

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.

<blockquote>But it does fill the viewport! The whole page is green!</blockquote>

I know. But let's add borders to the `html` element to see what happens:

{% codepen https://codepen.io/bcalou/pen/zYvJJzY %}

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.

<blockquote>So WHY the green everywhere?</blockquote>

Same answer from the w3c :

<blockquote>The background of the root element becomes the background of the canvas.</blockquote>

[We also learn](https://www.w3.org/TR/css-backgrounds-3/#body-background) that the root element can be the `body` or the `html` :

<blockquote>It is recommended that authors of HTML documents specify the canvas background for the BODY element rather than the HTML element.</blockquote>

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:

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

<figure>
![Mix blend mode examples](https://dev-to-uploads.s3.amazonaws.com/i/dskw2u8s72jwjr8mqmsi.jpg)
<figcaption>From www.visualcinnamon.com</figcaption>
</figure>

We begin with a simple example: the `h1` will be green, and we want to change its appearance with `mix-blend-mode: difference`.

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

{% codepen https://codepen.io/bcalou/pen/YzyOJEO %}

It is not, I repeat, it is **not** pink.

<blockquote>But it should blend! The background is white!</blockquote>

No, it isn't. It's transparent.

![Ah ah!](https://dev-to-uploads.s3.amazonaws.com/i/8gy1spv4e86tgrrts20v.jpg)

The difference between green and transparent is green, hence the color of the title, unchanged.

Let's recap:
* The `body` is transparent (default value of `background-color`)
* The `html` is transparent (default value of `background-color`)
* The canvas is transparent (no value provided by `html` nor `body`)

So our poor title has nothing to blend with.

The fix is easy: just put a `background-color` on the `body` !

```css
body {
  background-color: white;
}
```

It now works!

{% codepen https://codepen.io/bcalou/pen/wvKEYGO %}

Let's recap again:
* The `body` is `transparent` (`white` set in the CSS, but "stolen" by the canvas)
* The `html` is transparent (default value of `background-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.

<blockquote>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!</blockquote>

Hear me out. What if there is *another* layer, actually white, below the canvas?

![There must be another layer](https://dev-to-uploads.s3.amazonaws.com/i/8pkuwz4cm80w6a23ij8e.jpg)

Once again, the [w3c](https://www.w3.org/TR/css-backgrounds-3/#body-background) gives the answer:

<blockquote>If the canvas background is not opaque, what shows through is UA-dependent.</blockquote>

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:

```css
html, body {
  border: 3px dashed black;
}
```

Our page looks like that:

{% codepen https://codepen.io/bcalou/pen/ExVdbgE %}

Let's include that page in another one with an `iframe` tag:

```html
<iframe src="..." width="100%" height="300px"></iframe>
```

Here's what we get :

{% codepen https://codepen.io/bcalou/pen/GRpYOjV %}

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.

```css
body {
  background-color: lightblue;
}
```

{% codepen https://codepen.io/bcalou/pen/ExVdbNL %}

As you can see, the iframe is transparent. `body`, `html`, and canvas. We can see the parent page through it.

<blockquote>Does it really prove that the canvas is transparent? Maybe iframes just don't have a canvas?</blockquote>

That's a fair question. To answer that, let's put a white background on the `iframe`'s `body` tag:

```css
body {
  background-color: white;
}
```

Here's what we get:

{% codepen https://codepen.io/bcalou/pen/mdezqON %}

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.

![That's so deep](https://dev-to-uploads.s3.amazonaws.com/i/o4353if5qaxyjzvnptp8.gif)

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` and `body`, so transparent by default)
* The inaccessible software foundations (often white)

Oh, and I tried to represent it visually :

<figure>
![](https://dev-to-uploads.s3.amazonaws.com/i/nmtmi70rm29s4e0ogcha.jpg)
<figcaption>It's a small Hello World after all</figcaption>
</figure>


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.