contain 屬性
這個 contain 屬性的主要目的是隔離指定內容的樣式、布局和渲染。開發人員可以使用這個 contain 屬性來限制指定的DOM元素和它的子元素同頁面上其它內容的聯系;我們可以把它看做一個iframe。跟iframe很相似,它能建立起一個邊界,產生一個新的根布局;保證了它和它的子元素的DOM變化不會觸發父元素重新布局、渲染等。
開發人員可以用這個 contain 屬性聲明一個元素和它的子元素是——盡可能的——和頁面上的其它元素保持獨立。— 來自 W3C 規范
contain 使用場景舉例
我們已經知道了,使用這個 contain 屬性可以將一個元素標志為和頁面上其它元素是相對獨立的元素。為了說明這個屬性的作用,下面舉幾個使用例子:
頁面小飾件(widgets)
通常在頁面上添加第三方小飾件時,我們幾乎對它們沒有什么太多的控制,比如分享工具,它們可能會因為具有相當耗資源的布局、樣式、渲染操作等大幅度的降低整個頁面的執行效率。為了將它們同我們的網站隔離開來,使用 contain: strict; 將第三方的小飾件同頁面上的其它內容隔離開來。
屏幕外的內容
如果你有一個導航欄或其它類似的東西並不在屏幕可現實范圍內出現,瀏覽器同樣會為這些不可見的元素進行渲染。通過使用 contain: paint; 瀏覽器就會忽略渲染這些屏幕外不可見的元素,從而能更快的渲染其它內容。
什么時候應該使用contain
如果你的頁面很簡單,沒有復雜的DOM節點和小飾件(widgets),那就沒必要考慮使用這種css的contain技術。而如果你開發的頁面非常復雜,那么,這個css的contain技術可以幫助你優化頁面的性能。而對於第三方的小飾件,始終使用contain: strict;是很好的習慣,它可以保護你的頁面不受它們的干擾而出現性能問題。
contain 語法
看看它的語法:
{
/* No layout containment. */ contain: none; /* Turn on size containment for an element. */ contain: size; /* Turn on layout containment for an element. */ contain: layout; /* Turn on style containment for an element. */ contain: style; /* Turn on paint containment for an element. */ contain: paint; /* Turn on containment for layout, paint, and size. */ contain: strict; /* Turn on containment for layout, and paint. */ contain: content; }
none | strict | layout | style | paint | size | contain
這個 contain 屬性可以有7種不同的值。
- none 無
- layout 開啟布局限制
- style 開啟樣式限制
- paint 開啟渲染限制
- size 開啟size限制
- content 開啟除了size外的所有限制
- strict開啟 layout, style 和 paint 三種限制組合
除去 none,取值還有 6 個,我們一個一個來看看。
contain: size
contain: size: 設定了 contain: size 的元素的渲染不會受到其子元素內容的影響。
我開始看到這個定義也是一頭霧水,光看定義很難明白到底是什么意思。還需實踐一番:
假設我們有如下簡單結構:
<div class="container"> </div>
.container { width: 300px; padding: 10px; border: 1px solid red; } p { border: 1px solid #333; margin: 5px; font-size: 14px; }
並且,借助 jQuery 實現每次點擊容器添加一個 <p>Coco</p> 結構:
$('.container').on('click', e => { $('.container').append('<p>Coco</p>') })
那么會得到如下結果:
可以看到,容器 .container 的高度是會隨着元素的增加而增加的,這是正常的現象。
此刻,我們給容器 .container 添加一個 contain: size,也就會出現上述說的:設定了 contain: size 的元素的渲染不會受到其子元素內容的影響。
.container {
width: 300px;
padding: 10px;
border: 1px solid red;
+ contain: size
}
再看看會發生什么:
正常而言,父元素的高度會因為子元素的增多而被撐高,而現在,子元素的變化不再影響父元素的樣式布局,這就是 contain: size 的作用。
contain: style
接下來再說說 contain: style、contain: layout 、contain: paint。先看看 contain: style。
截止至本文書寫的過程中,contain: style 暫時被移除了。
嗯,官方說辭是因為存在某些風險,暫時被移除,可能在規范的第二版會重新定義吧,那這個屬性也暫且放一放。
contain: paint
contain: paint:設定了 contain: paint 的元素即是設定了布局限制,也就是說告知 User Agent,此元素的子元素不會在此元素的邊界之外被展示,因此,如果元素不在屏幕上或以其他方式設定為不可見,則還可以保證其后代不可見不被渲染。
這個稍微好理解一點,先來看第一個特性:
設定了 contain: paint 的元素的子元素不會在此元素的邊界之外被展示
設定了 contain: paint 的元素的子元素不會在此元素的邊界之外被展示
這個特點有點類似與 overflow: hidden,也就是明確告知用戶代理,子元素的內容不會超出元素的邊界,所以超出部分無需渲染。
簡單示例,假設元素結構如下:
<div class="container"> <p>Coco</p> </div>
.container { contain: paint; border: 1px solid red; } p{ left: -100px; }
我們來看看,設定了 contain: paint 與沒設定時會發生什么:
設定了 contain: paint 的元素在屏幕之外時不會渲染繪制
通過使用 contain: paint, 如果元素處於屏幕外,那么用戶代理就會忽略渲染這些元素,從而能更快的渲染其它內容。
https://www.98891.com/article-25-1.html
contain: layout
contain: layout:設定了 contain: layout 的元素即是設定了布局限制,也就是說告知 User Agent,此元素內部的樣式變化不會引起元素外部的樣式變化,反之亦然。
This value turns on layout containment for the element. This ensures that the containing box is totally opaque for layout purposes; nothing outside can affect its internal layout, and vice versa.
啟用 contain: layout 可以潛在地將每一幀需要渲染的元素數量減少到少數,而不是重新渲染整個文檔,從而為瀏覽器節省了大量不必要的工作,並顯着提高了性能。
使用 contain:layout,開發人員可以指定對該元素任何后代的任何更改都不會影響任何外部元素的布局,反之亦然。
因此,瀏覽器僅計算內部元素的位置(如果對其進行了修改),而其余DOM保持不變。因此,這意味着幀渲染管道中的布局過程將加快。
存在的問題
描述很美好,但是在實際 Demo 測試的過程中(截止至2021/04/27,Chrome 90.0.4430.85),僅僅單獨使用 contain:layout 並沒有驗證得到上述那么美好的結果。
設定了 contain: layout 的指定元素,改元素的任何后代的任何更改還是會影響任何外部元素的布局,點擊紅框會增加一條 <p>Coco<p> 元素插入到 container 中:
簡單的代碼如下:
<div class="container"> <p>Coco</p> ... </div> <div class="g-test"></div>
html,
body { width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; flex-direction: column; gap: 10px; } .container { width: 150px; padding: 10px; contain: layout; border: 1px solid red; } .g-test { width: 150px; height: 150px; border: 1px solid green; }
目前看來,contain: layout 的實際作用不那么明顯,更多的關於它的用法,你可以再看看這篇文章:CSS-tricks - contain
contain: strict | contain: content
這兩個屬性稍微有點特殊,效果是上述介紹的幾個屬性的聚合效果:
contain: strict:同時開啟 layout、style、paint 以及 size 的功能,它相當於 contain: size layout paint
contain: content:同時開啟 layout、style 以及 paint 的功能,它相當於 contain: layout paint
所以,這里也提一下,contain 屬性是可以同時定義幾個的。
Can i Use -- CSS Contain
截止至 2021-04-27,Can i Use 上的 CSS Contain 兼容性,已經可以開始使用起來: