阅读 1848

HTML/BODY的背景渲染原理

一、前言

结论先行:

我们给body设置背景色,实际我们看见的未必是body上的背景色:

  1. 当html标签没有设置背景色时,我们看见的是作用在浏览器画布上的背景色,不是body上的;
  2. 当html标签被设置了背景色时,我们看见的是真正作用在body上的背景色。

人在前端已经漂泊数年,机缘巧合才发现,这几年给body写的背景色,全被浏览器给「吃」了。文中涉及的是CSS中关于特殊元素(html/body)的背景渲染的原理,对你而言它也许是块新大陆,也可能,你早已熟知,那么正好···可以一起交流下?

二、一个情景

有一个渲染列表的页面(不定高),要求背景是渐变颜色,效果如下图:

需求很简单:

  • 列表内容不足以撑满一屏时,整屏背景以渐变色填充;
  • 列表内容超过一屏高度时,整个页面背景以渐变色填充;

三、情景破解

姿势有很多,偏爱的只有妳这一种。

PS:破解情景的解法有很多,而下面这种解法可以引起我们关于html、body背景渲染原理的思考。

Step 1:首先给body设置颜色渐变
body{ background: linear-gradient(#FFFAD0,#ffffff); }
复制代码

不出意外,页面渐变出现了断层👇

Step 2:设置html高度为100%,同时给body设置下min-height
html{ height: 100%;}
body{ min-height: 100%; background: linear-gradient(#FFFAD0,#ffffff); }
复制代码

又不出意外,看起来很OJBK,没有出现断层了!

突然,内容渐渐多了起来,超过一屏的高度了···👇

呃···这是什么情况?超过一屏之后又断层了![what the fuck & 掀桌].jpg

Step3:设置html的背景色
html{ height: 100%; background: red; }
复制代码

是的,你没看错,我给html设置了红色!不得不服气,这样的骚操作竟然解决了上面断层的问题。

突然兴起的总结

小小梳理下我们遇到的疑点:

  1. 首先我们给body设置了渐变色,即使内容超过一屏,我们看到的也应该是body那一层,即是渐变色的背景,不应该断层!
  2. 为什么给html元素设置一个背景色就可以完美解决这个断层?

四、原理解析

我们这个问题涉及到了三个对象:html元素、body元素和浏览器画布,我们需要了解它们三者之间渲染背景色的机制。

The document canvas is the infinite surface over which the document is rendered. [CSS2] Since no element corresponds to the canvas, in order to allow styling of the canvas CSS propagates the background of the root element (or, in the case of HTML, the element) as described below. However, if no boxes are generated for the element whose background would be used for the canvas (for example, if the root element has display: none), then the canvas background is transparent.

The background of the root element becomes the background of the canvas and its background painting area extends to cover the entire canvas. However, any images are sized and positioned relative to the root element as if they were painted for that element alone. (In other words, the background positioning area is determined as for the root element.) The root element does not paint this background again, i.e., the used value of its background is transparent.

以上是w3c对特定元素(根元素)背景的定义说明,总结为以下两点:

  • CSS根据根元素(html/body)给文档画布(该画布是无限大的,我们姑且理解为浏览器画布)渲染背景颜色,同时背景色的定位区域就是根元素的区域;
  • 根元素不再绘制该背景色,即根元素背景的使用值是透明的。

基于这两点解答前面我们的疑问:

1、给body设置了渐变色背景,内容超过一屏的时候,出现了断层

真相是,浏览器画布首先获取根节点的背景样式,由于html我们没有设置,所以它获取了body的背景色,从而导致浏览器画布也是渐变色背景;

其次,浏览器画布背景色的定位区域取决于根元素的区域,这里的根元素是html,而我们对html做了 height:100% 的设置。所以浏览器画布以该区域的背景色重复渲染。

用图举证: 给html设置50%的width,那么左侧看到的是我们的页面dom内容,右侧则是浏览器画布

html{ height: 100%; width: 50%; }
body{ min-height: 100%; background: linear-gradient(#FFFAD0,#ffffff); }
复制代码

可以发现,左右两侧的背景色是一致的:
证明了浏览器画布取了body的背景色进行渲染,而body的背景色其实是透明值,必然地,我们在body看见的是会断层的渐变色。

所以,我们给body设置的背景色被浏览器画布吃掉了!

2、通过html设置背景色的方式解决了断层问题

我们给html设置背景色,其实是让html去承担被浏览器画布取色的任务,这时候body的值就是我们设置的渐变色。以图举证:

html{ height: 100%; width: 50%; background: #42b983; }
复制代码

对的,红色不喜欢,我决定了换成vue的主题绿。如此,浏览器画布取了html的背景色,左侧就可以正常看见body的渐变背景了。

五、结语

以上提及的知识点也许很基础,它只是w3c里面关于背景渲染的标准,只不过被我们很多人忽略而已。现在踩坑,记之共勉。

参考

Applying a background to and/or

Backgrounds of Special Elements

关注下面的标签,发现更多相似文章
评论