1. 程式人生 > 其它 >CSS新特性contain的語法、作用及使用場景

CSS新特性contain的語法、作用及使用場景

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 相容性,已經可以開始使用起來: