熟悉又陌生的containing block

Nekron發表於2019-03-01

什麼是containing block?

如果幹巴巴的問一個前端什麼是containing block。大部分都不知所云。官方示意如下:

The size and position of an element are often impacted by its containing block. Most often, the containing block is the content area of an element`s nearest block-level ancestor, but this is not always the case. In this article, we examine the factors that deterime an element`s containing block.

簡單來說就是——無特殊情況下,containing block(包含塊)就是最近的塊元素的content area(內容區)

什麼是內容區?

以這個經典的盒模型圖:

熟悉又陌生的containing block

最內部的即為內容區。

我們平時用到過嗎?

這個概念雖然可能不熟悉,但是實際上我們經常用到:

/*
<div class="outer">
    <div class="inner"></div>
</div>
*/
.outer {
    width: 200px;
    box-sizing: border-box;
}
.inner {
    width: 80%;
}
複製程式碼

inner的寬度是多少呢?毫無疑問,是160px。那稍微加一點戲,如果outer增加一條屬性padding: 50px,這時候inner的寬度是多少?

很多人會遲疑一下,因為不知道背後的原理,只能根據經驗推斷,如果經驗老道,會給出正確答案:80px

實際上,這些百分比值的運作原理都是通過包含塊來計算出最後結果。再回想一下之前的規範,包含塊是最近的塊元素的內容區,就可以很清晰的理解padding值在這個例子中起的作用了。

元素的尺寸和位置經常受其包含塊的影響。

特殊情況

如果敏感的人看到這可能會產生一個疑惑,如果把例子改成這樣?

.outer {
    position: relative;
    width: 200px;
    padding: 50px;
    box-sizing: border-box;
}
.inner {
    position: absolute;
    width: 80%;
}
複製程式碼

這時候inner width又是多少呢?是160px

熟悉又陌生的containing block

好不容易剛消化的知識就給了當頭一棍。。。然後回想一下平時用的時候好像確實是這樣!

所以規範提到了無特殊情況下,而特殊情況是:

  • 如果position是absolute,包含塊就是它最近的position值不是static的元素的padding area
  • 如果position是fixed,包含塊就是檢視。
  • 如果position是absolutefixed,包含塊是最近的滿足下列條件的元素的padding area
    • transform或perspective值不是none
    • filter值不是none
    • will change值包含transform、perspective、或filter(只有Firefox有效)

position: fixed

瞭解了包含塊的規範,可以更好的理解平時常用的一些特性的執行原理。而特殊情況的最後一點,其實還有一些場景可以利用。

比如如下場景:

引入了一個三方ui庫,內部有一個彈窗元件,很正常的使用了fixed定位,那它的包含塊就是檢視了。如果這時,需要將它的位置進行調整,那怎麼辦?

可以利用transform/perspective/filter來改變這個彈窗所在的內容塊,從而起到定位的作用。

contain

理解了包含塊,能夠將特性運用到一些特定場景中,已經說明知識點消化的足夠好了。但是下面的彩蛋知識點,還需要一點運氣才能獲得~因為它並沒有在包含塊的MDN文件中被提及。

chrome率先實現了一個實驗特性contain。它允許開發者宣告當前元素和它的內容儘可能的獨立於 DOM 樹的其他部分。從而使得瀏覽器在重新計算佈局、樣式、繪圖或它們的組合的時候,只會影響到有限的 DOM 區域,而不是整個頁面。

在它的可選值中,paint的作用是使得該元素的子孫節點不會超出它的邊緣。

那父元素contain: paint和子元素position: fixed結合會如何呢?

實驗結果是,fixed的元素表現得像是父元素設定了transform/perspective/filter一樣,說明它的包含塊被contain: paint屬性所影響。

MDN文件中沒提到,那是Chrome意外實現了一個彩蛋嗎?

熟悉又陌生的containing block

確認了規範以後證實,Chrome並不是xjb實現的~

The element acts as a containing block for absolutely positioned and fixed positioned descendants.

參考

  1. Layout and the containing block
  2. contain
  3. containment-paint

相關文章