CSS新特性contain,控制頁面的重繪與重排

在介紹新的 CSS 屬性 contain 以前,讀者首先須要瞭解什麼是頁面的重繪與重排。javascript

以前已經描述過不少次了,還不太瞭解的能夠先看看這個提升 CSS 動畫性能的正確姿式css

OK,下面進入本文正題,html

contain 爲什麼?

contain 屬性容許咱們指定特定的 DOM 元素和它的子元素,讓它們可以獨立於整個 DOM 樹結構以外。目的是可以讓瀏覽器有能力只對部分元素進行重繪、重排,而沒必要每次都針對整個頁面。java

The contain property allows an author to indicate that an element and its contents are, as much as possible, independent of the rest of the document tree. This allows the browser to recalculate layout, style, paint, size, or any combination of them for a limited area of the DOM and not the entire page.

contain 語法

看看它的語法:git

{
  /* 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,取值還有 6 個,咱們一個一個來看看。github

contain: size

contain: size: 設定了 contain: size 的元素的渲染不會受到其子元素內容的影響。web

The value turns on size containment for the element. This ensures that the containing box can be laid out without needing to examine its descendants.

我開始看到這個定義也是一頭霧水,光看定義很難明白究竟是什麼意思。還需實踐一番:瀏覽器

假設咱們有以下簡單結構:app

<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> 結構:ide

$('.container').on('click', e => {
    $('.container').append('<p>Coco</p>')
})

那麼會獲得以下結果:

containsize

能夠看到,容器 .container 的高度是會隨着元素的增長而增長的,這是正常的現象。

此刻,咱們給容器 .container 添加一個 contain: size,也就會出現上述說的:設定了 contain: size 的元素的渲染不會受到其子元素內容的影響

.container {
    width: 300px;
    padding: 10px;
    border: 1px solid red;
+   contain: size
}

再看看會發生什麼:

containsize2

正常而言,父元素的高度會由於子元素的增多而被撐高,而如今,子元素的變化再也不影響父元素的樣式佈局,這就是 contain: size 的做用。

contain: style

接下來再說說 contain: stylecontain: layoutcontain: paint。先看看 contain: style。

截止至本文書寫的過程當中,contain: style 暫時被移除了。

CSS Containment Module Level 1: Drop the at-risk 「style containment」 feature from this specification, move it Level 2。

嗯,官方說辭是由於存在某些風險,暫時被移除,可能在規範的第二版會從新定義吧,那這個屬性也暫且放一放。

contain: paint

contain: paint:設定了 contain: paint 的元素便是設定了佈局限制,也就是說告知 User Agent,此元素的子元素不會在此元素的邊界以外被展現,所以,若是元素不在屏幕上或以其餘方式設定爲不可見,則還能夠保證其後代不可見不被渲染。

This value turns on paint containment for the element. This ensures that the descendants of the containing box don’t display outside its bounds, so if an element is off-screen or otherwise not visible, its descendants are also guaranteed to be not visible.

這個稍微好理解一點,先來看第一個特性:

設定了 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 與沒設定時會發生什麼:

containsize3

CodePen Demo -- contain: paint Demo

設定了 contain: paint 的元素在屏幕以外時不會渲染繪製

經過使用 contain: paint, 若是元素處於屏幕外,那麼用戶代理就會忽略渲染這些元素,從而能更快的渲染其它內容。

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;
}

CodePen Demo -- contain: layout Demo

目前看來,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 兼容性,已經能夠開始使用起來:

參考文獻

最後

好了,本文到此結束,但願對你有幫助 :)

更多精彩 CSS 技術文章彙總在個人 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

若是還有什麼疑問或者建議,能夠多多交流,原創文章,文筆有限,才疏學淺,文中如有不正之處,萬望告知。

相關文章
相關標籤/搜索