一、前言
結論先行:
我們給body設定背景色,實際我們看見的未必是body上的背景色:
- 當html標籤沒有設定背景色時,我們看見的是作用在瀏覽器畫布上的背景色,不是body上的;
- 當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設定了紅色!不得不服氣,這樣的騷操作竟然解決了上面斷層的問題。
突然興起的總結
小小梳理下我們遇到的疑點:
- 首先我們給body設定了漸變色,即使內容超過一屏,我們看到的也應該是body那一層,即是漸變色的背景,不應該斷層!
- 為什麼給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裡面關於背景渲染的標準,只不過被我們很多人忽略而已。現在踩坑,記之共勉。
參考