你知道空白网页的颜色是什么吗?

若是下面这段代码,在浏览器中打开。最终的页面颜色是什么?css

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

It's a CSS trap!

你可能意识到这个是陷阱问题,大部分同窗会说是白色,但页面其实并非白色的: 它是透明的。这是由于浏览器的底色是白色的,咱们透过了页面的透明色,看到了浏览器的底色而已。html

证实页面是无色的

若是咱们但愿有一个黄色背景的页面,咱们能够在 body 上添加一个背景色:前端

body {
  background-color: yellow;
}

image-20200619092016781

咱们看到的整个页面背景都是黄色,确定有同窗会认为:这是因为 body 填充了整个视图窗口。算法

但这不是真的,若是咱们在 body 上添加一个边框:canvas

body {
  background-color: yellow;
  border: 3px dashed black;
}

image-20200619092049570

您能够看到,其实 body 只包裹了 Hello World 内容区域。浏览器

为何整个页面都是黄色的?

咱们来看看 w3c:fetch

根元素的背景将成为 canvas 的背景,其背景绘制区域扩展到覆盖整个 canvas。

大白话解释一下:若是你在 body 上设置一个背景。浏览器将使用这个背景做为 canvas 的背景。spa

问题又来了,什么是 canvas日志

canvas 是浏览器在渲染页面时,生成的画布,页面上的全部内容都会在画布上进行渲染。

这个 canvas 是至关大的。code

尽管 canvas 是浏览器中一个很是重要的部分,但相关的资料却很是少。正如咱们看到的,canvas 基于 body,为整个视区(viewport)提供了一个背景。

有很长一段时间,我认为 canvas 就是 body,可是 canvas 只是使用了 body 的信息,canvas 自己可比 body 大得多。

有趣的是,即便咱们将 body 设置为黄色,实际上 body 真实的颜色仍然是透明的。 正如 w3c 所言:

当根元素的背景成为 canvas 的背景后,浏览器将不会再绘制根元素的背景,根元素的背景实际值是透明的。

对于浏览器来讲,绘制与 canvas 颜色相同的 body 是没有意义的,这也是它透明的缘由。

换句话说:当您在 body 上设置背景色时,您其实是在设置 canvas 背景。 canvas 从 body 上“偷走”了背景色。

影响 Canvas 的根元素

其实影响 canvas 的元素不仅 body,还有 html,咱们来依次分析一下。

先来看看什么是 body 元素?

根据 w3c 的说法,body 是展现内容的地方,包括:文本、图像、颜色、图形等。

若是 body 用来展现内容,那么 body 以外的东西就不能展现内容。

Yes, thank you for your input

因此你们是否会有这样一个疑问:在 html 元素上设置一个背景色不会有任何效果,由于它不是内容的一部分?

咱们仔细想想: 下面这个页面会显示成什么样子?

html {
  background-color: green;
}

body {
  background-color: yellow;
}

如今页面的颜色是什么?是黄色仍是绿色?仍是二者都有?

image-20200619092123439

答案是:二者都有。

当前页面上咱们能看到什么?

  • body 元素的黄色背景仅限于内容部分。
  • html 元素的背景彷佛占据了整个视图窗口。

错!咱们又一次被愚弄了。

让咱们给 html 元素添加边框,看看会发生什么:

image-20200619092151820

因此实际上,html 的行为就像 body 同样:它的大小也是根据页面内容动态渲染的。

为何当前整个页面都是绿色呢?

W3c 给出了一样的答案:

  • 根元素的背景将成为 canvas 的背景。
  • W3c 中指的根元素能够是 body 或者 html。

因此,与第一个示例同样,html 真正的颜色是透明的,它的绿色被 canvas “偷走”了。

咱们如今有了浏览器用来选择 canvas 颜色的完整算法:

if (html 存在背景颜色) {
  // 使用 html 的背景颜色,做为 canvas 的背景
}
else if (body 存在背景颜色) {
  // 使用 body 的背景颜色,做为 canvas 的背景
}
else {
  // 使用 canvas 的默认透明颜色
}

好吧,我想这个谜团解开了。 你能够认为 w3c 这样作是至关聪明的,咱们不用给根元素设置明确的尺寸,就能让根元素的背景色填充整个视口。

白色和透明色

理解白色和透明之间的区别,是解决一些 css 之谜的关键。

让咱们玩一玩 css 中的在混合模式 mix-blend-mode。 这个 css 属性容许咱们定义一个元素应该如何与它的父元素混合。 有时被称为“浏览器中的 Photoshop”。 无论有没有夸大,这个属性都是很是厉害的。

Mix blend mode examples

咱们从一个简单的示例开始:

h1 {
  color: green;
  mix-blend-mode: difference;
}

上面的实例表示,咱们经过 mix-blend-mode 去改变原本为绿色的 h1 标题, mix-blend-mode: difference 意味着将文本的颜色改变成:原始颜色(绿色)与背景颜色之间的混合色值。

between(绿色 + 白色)= 粉红色,因此但愿咱们的标题是粉红色。

image-20200619092216000

但事实证实,它不是粉红色的。

若是背景色是白色的话,混合出来的颜色就是粉红色的,但它不是,证实当前的背景色并非白色,事实上是透明色。

Ah ah!

between(绿色 + 透明)= 绿色,所以标题的颜色没有变化。

让咱们回顾一下:

  • body 是透明的
  • html 是透明的
  • canvas 是透明的(因为没有设置 html 或 body 的背景)

因此咱们的 h1 没有什么能够混合的。

解决方法很简单:只须要在 body 上添加一个背景色便可!

body {
  background-color: white;
}

它如今起做用了!

image-20200619092247864

让咱们再来理一理:

  • body 是透明的,它的背景被 canvas 偷走了
  • html 是透明的,默认
  • canvas 是白色的,它偷走了 body 的颜色

因此咱们的绿色标题与 canvas 融合,变成粉红色。 这个标题固然能够是一张图片,一段视频,任何东西。

咱们的话题即将结束,但还有最后一个问题。。。

Canvas 的默认颜色

到目前为止,咱们理想中的页面层级(从上到下)是这样的:

  • body 元素
  • html 元素
  • canvas 画布

根据咱们所学到的,若是 body 和 html 是透明的,那么画布也是透明的。

可是最底层的 canvas 怎么多是透明的呢? 若是是这样的话,咱们能够经过浏览器看到桌面和其余窗口!

听我说完,若是在下面还有另外一层,其实是白色的呢?

There must be another layer

w3c 再次给出了答案:

若是 canvas 背景是透明的,那么所显示的背景是依赖于用户界面(UA-dependent)

用大白话说:在 canvas 后面还有一个用户界面,若是 canvas 是透明的,你能够看到它。你看到什么取决于浏览器。

目前我见过的全部浏览器中,用户界面底层都是白色的。

有什么办法能够真正看出白色和透明 canvas 之间的区别? 让咱们能证实 canvas 默认是透明的吗?

经过 Iframe 证实

让咱们回到一个很是简单的 css:

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

咱们的页面是这样的:

image-20200619092457997

让咱们用 iframe 标签把这个页面包含在另外一个页面中:

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

如下是咱们获得的结果:

image-20200619092517445

因此,问题是: iframe 是有一个透明的仍是白色的 canvas?

咱们能够经过在父页面上设置背景色来回答这个问题。

body {
  background-color: lightblue;
}

image-20200619091815769

如您所见,iframe 的 canvas 是透明的,咱们能够透过它看到父页面。

它真的能证实 canvas 是透明的吗? 也许 iframe 就是没有 canvas?

这是一个很好的问题,为了回答这个问题,让咱们在 iframe 的 body 标签上加上一个白色背景:

body {
  background-color: white;
}

如下是咱们获得的结果:

image-20200619091841730

若是 iframe 没有 canvas,那么它 body 外部的区域就不会被填充。 可是因为 canvas 机制,body 的背景颜色能够用来覆盖整个 iframe 视区。

这就是为何咱们能够在任何页面上看到,默认的画布不是白色的,而是透明的

因此当你打开一个空白页面时,你看到的不是一个白色的画布。 它只是浏览器的“底部” ,是浏览器这个软件的背景色。

That's so deep

所以,咱们获得的浏览器最终的层级是这样的(从上到下):

  • body 元素(默认透明)
  • html 元素(默认透明)
  • canvas(依赖于html 及body, 默认透明)
  • 浏览器的背景(一般是白色的)

用一张三维图来看一下:

img

总结

咱们经过几段 css 代码,咱们发现了浏览器存在一个绘图区 canvas,这个绘图区是很是大的,这个绘图区会受页面根元素的影响:

绘图区域的颜色计算:

  • 若是有定义 html 的背景色,则为 html 的背景色。
  • 若是没有定义 html 背景色,但有定义 body 的背景色,则为 body 的背景色。
  • 若是没有定义 html 和 body 的背景色,则为透明背景色。

最后,若是你对此有任何想法,欢迎留言评论!

前端日志

相关文章
相关标签/搜索