作者:HaoyCn

http://segmentfault.com/a/1190000003825614

前言:關於層疊上下文,筆者還沒有去閱讀更詳細的 W3C 規範來瞭解更本質的原理(表打我,等我校招拿到 offer 了我就讀好伐 T_T)。一直聽說 CSS3 裏的層疊上下文有新情況,但沒找到很好的參考資料,故自己實戰一把。鑑於筆者水平有限,如有任何遺漏或者錯誤,則懇請讀者斧正。

1 CSS2.1 中規定的層疊上下文

CSS3 中的層疊上下文初探

Background and borders — of the element forming the stacking context. The lowest level in the stack.

Negative Z-Index — the stacking contexts of descendants elements with negative z-index.

Block Level Boxes — in-flow non-inline-level non-positioned descendants.

Floated Boxes — non-positioned floats

Inline Boxes — in-flow inline-level non-positioned descendants.

Z-index: 0 — positioned elements. These form new stacking contexts.

Positive Z-index — positioned elements. The highest level in the stack.

現在該筆者上場翻譯了!在解釋上面術語之前,需要闡明兩個術語:“定位”指的是 position 爲 relative 、absolute、fixed 的元素,“非定位”則相反。

  • 背景和邊框:建立層疊上下文元素的背景和邊框。層疊中的最低級
  • 負 Z-index:z-index 爲負的後代元素建立的層疊上下文
  • 塊級盒:文檔流內非行內級非定位後代元素
  • 浮動盒:非定位浮動元素(筆者注:即排除了 position: relative 的浮動盒)
  • 行內盒:文檔流內行內級非定位後代元素
  • Z-index: 0:定位元素。這些元素建立了新層疊上下文(筆者注:不一定,詳見後文)
  • 正 Z-index:(z-index 爲正的)定位元素。層疊的最高等級

引文如上所表。但筆者提醒各位讀者一點,“Z-index: 0”級的定位元素不一定就會建立新的層疊上下文。因爲:

CSS2.1:(z-index: auto)The stack level of the generated box in the current stacking context is 0. The box does not establish a new stacking context unless it is the root element.

當定位元素 z-index: auto,生成盒在當前層疊上下文中的層級爲 0。但該盒不建立新的層疊上下文,除非是根元素。

規範是這樣,但 IE6-7 有個 BUG,定位元素即便 z-index: auto 照樣創建層疊上下文。

以上是基於 CSS2.1 的層疊上下文介紹。下面要闡述的是在 CSS3 新環境下,層疊上下文的新變化。

2 CSS3 帶來的變化

總的來說變化可以歸爲兩點,我們之後一一探討:

  • CSS3 中許多屬性會創建局部層疊上下文
  • tranform 屬性改變絕對定位子元素的包含塊

2.1 產生新層疊上下文的情況

以下情況會產生新的層疊上下文:

  • 根元素(HTML)
  • 絕對或相對定位且 z-index 值不爲 auto
  • 一個伸縮項目 Flex Item,且 z-index 值不爲 auto,即父元素 display: flex|inline-flex
  • 元素的 opacity 屬性值小於 1
  • 元素的 transform 屬性值不爲 none
  • 元素的 mix-blend-mode 屬性值不爲 normal
  • 元素的 filter 屬性值不爲 normal
  • 元素的 isolation 屬性值爲 isolate
  • position: fixed
  • will-change 中指定了上述任意屬性,即便你沒有直接定義這些屬性
  • 元素的 -webkit-overflow-scrolling 屬性值爲 touch

以上列表譯自:

https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context,提醒廣大讀者,別看中文版,因爲中文版並非實時跟進更新的,且翻譯不太準確

2.2 提升層疊上下文中的層級

以上元素建立新層疊上下文的同時,也會提升元素自身所在層疊上下文中的層級。

我們以 opacity 爲例。來看下 CSS3 規範中的話:

If an element with opacity less than 1 is not positioned, implementations must paint the layer it creates, within its parent stacking context, at the same stacking order that would be used if it were a positioned element with ‘z-index: 0’ and ‘opacity: 1’. If an element with opacity less than 1 is positioned, the ‘z-index’ property applies as described in [CSS21], except that ‘auto’ is treated as ‘0’ since a new stacking context is always created.

如果元素 opacity 小於 1 且未定位,則必須在其父層疊上下文中,按其在定位了的、z-index: 0 且 opacity: 1 的情況中的層疊順序繪製。如果 opacity 小於 1 且已定位,z-index 屬性按 CSS2.1 應用,但 auto 要視爲 0,因爲新的層疊上下文總是創建了的。

如下案例:

div {

width: 100px;

height: 100px;

}

#box1 {

position: absolute;

background: red;

top: 40px;

left: 40px;

}

#box2 {

background: blue;

}

以上 CSS 和 HTML 片段中,由於 box1 是絕對定位(層級爲“Z-index: 0”級),而 box2 是文檔流內塊級盒(層級爲“塊級盒”級),因此 box1 會層疊在 box2 之上。下面添加如下 CSS 規則:

#box2 {

opacity: .5;

}

這時候, box2 則會層疊在 box1 之上了。因爲 box2 的 opacity 爲 0.5(小於 1),故視其爲“Z-index: 0”級,也就和 box1 同級了。同級情況下,按照二者在源代碼中的順序,居後的 box2 又重新佔領高地了。

讀者可以取下面規則之任意一條實驗,都能達到同樣效果:

#box2 {

transform: scale(1);

mix-blend-mode: difference;

isolation: isolate;

-webkit-filter: blur(5px);

}

2.3 transform 改變絕對定位子元素包含塊

transform 除了建立新的局部層疊上下文外,還會幹一件事:改變絕對定位子元素的包含塊。須注意的是,固定定位也是絕對定位的一種。

什麼是包含塊?有時候一些盒子根據矩形盒計算自身定位和大小,此矩形盒即包含塊。更多詳情請閱讀視覺格式化模型詳述。

固定定位元素

固定定位元素的包含塊由視口創建(如果讀者瞭解視覺格式化模型詳述的信息,也就知道這一點:在計算其“靜態位置”的時候,則以初始化包含塊作爲其計算包含塊)。現在我們看以下源代碼:

div {

width: 100px;

height: 100px;

}

#fixed {

position: fixed;

width: 100%;

height: 100%;

top: 0;

left: 0;

background: blue;

}

#transform {

background: red;

padding: 20px;

}

這個時候,以視口爲包含塊進行定位和大小計算, fixed 將會鋪滿整個屏幕。

但現在,我們加上如下規則:

#transform {

transform: scale(1);

}

此時,fixed 的包含塊不再是視口,而是 transform 的內邊距盒的邊緣盒了。故此時 fixed 的寬高均爲 140px。

絕對定位元素

我們舉一個例子:

#relative {

position: relative;

width: 100px;

height: 100px;

background: green;

}

#absolute {

position: absolute;

width: 100%;

height: 100%;

top: 0;

left: 0;

background: blue;

}

#transform {

background: red;

width: 50px;

height: 50px;

}

此時 absolute 的包含塊爲 relative 的內邊距盒的邊緣盒。由此 absolute 的寬高均爲 100px。然後我們添加如下規則:

#transform {

transform: scale(1);

}

由於 transform 創建了局部層疊上下文,absolute 的包含塊不再是 relative 而是 transform 了,根據這一新的包含塊,得新寬和高爲 50px。

相關文章