排版時無論 z-index 怎麼調,元素仍被其他東西蓋住——這個經驗背後的原因,與堆疊環境(Stacking Context)有關。

z-index#

z-index 用來指定元素在 z 軸的「高度」,越大越靠近使用者。CSS2.1 規格指明:

For a positioned box, the ‘z-index’ property specifies:

  • The stack level of the box in the current stacking context.
  • Whether the box establishes a stacking context.

positioned box 指 position 屬性不為預設值(static)的元素(box 指盒模型)。z-index 指定元素在堆疊環境中的堆疊層級,且只在 positioned box 上生效。

那麼堆疊環境究竟是什麼?

堆疊環境 Stacking Context#

網頁排版時,元素預設由上到下、由左到右依序排列。要調整或固定特定元素的位置,可設定 positionrelativeabsolutefixed,讓元素從原本位置移動,甚至離開正常流(Out of Flow)。

此時會產生新的 CSS 堆疊環境,這個元素與它的子元素自成一國,排列與其他堆疊環境無關。

功能#

堆疊環境對開發者的影響:堆疊環境內的元素、屬性變動,不會觸發其他堆疊環境的回流(Reflow)。

前一章討論的瀏覽器渲染步驟還有最後一步:Render Tree 經過計算會轉換成許多堆疊環境,可理解為圖層。先前提到的「計算定位(Layout、Reflow)」、「繪製像素(Paint)」發生在每一個圖層上,瀏覽器最後在「合成(Composite)」步驟疊加計算。

你可能會想問,為什麼不先疊加計算再繪製像素?

同樣的,是因為要讓各圖層的計算不會互相影響;如果某圖層只覆蓋到部分螢幕,當它樣式變動時,也只需要重算該圖層包含的部分畫面就好,不用全螢幕都重新繪製。

另外,堆疊環境也會影響到畫面的 z 軸排列順序。

回頭看一下剛剛提到的 z-index 定義,z-index 的影響範圍就只有在它所在的堆疊環境中;因此要確認兩元素的排列順序,必須先確認元素個別所在的堆疊環境順序,若在同一個堆疊環境,才比較兩者的 z-index

可以參考底下這個 MDN 的範例:

<div id="div1">...</div>
<div id="div2">...</div>
<div id="div3">
  <div id="div4">...</div>
  <div id="div5">...</div>
  <div id="div6">...</div>
</div>

範例中的 #div1#div2#div3 是同層元素,共用了最外層的「根堆疊環境(Root Stacking Context)」,而 #div4#div5#div6 則是 #div3 的子元素。

由於 #div3 有設定 position: absolutez-index: 3,它會產生一個新的堆疊環境,即使 #div2z-index 大於 #div5z-index,卻因為它們存在於不同的堆疊環境中,它們之間不會直接比較,而是從共用堆疊環境的 #div2#div3 中比較 z-index,來決定 z 軸上的排列順序。

建立堆疊環境#

要建立一個新的堆疊環境非常容易,比較常用到的有以下幾種方式:

  • 根元素(<html></html>
  • position 設定成 fixedsticky
  • position 設定成 relativeabsolute 且有設定 z-index
  • 有設定 transform 屬性
  • opacity 的值設定小於 1
.new-stacking-context {
  position: relative;
  z-index: 1;
}

.also-new {
  transform: translateZ(0);
}

.also-new-too {
  opacity: 0.99;
}

另外,開發者可以透過瀏覽器 DevTools 的 Layers 頁籤,觀察目前的頁面有哪些圖層。

如同前述,瀏覽器會將所有圖層做疊加運算;當圖層過多時也會稍微影響效能,在撰寫 CSS 時要稍微留心。

延伸閱讀#

雖然聊了兩天的 CSS 中相對深入的主題,但對於瀏覽器渲染畫面這塊仍然只帶到皮毛;關於 Render Tree 轉換成堆疊環境的過程,讀者如果想要進一步探究的話,可以參考相關文件深入研究。

結語#

許多原以為玄妙的 CSS 行為,例如絕對定位為什麼參考外層的 positioned box,都可以追溯到 Stacking Context。理解基本原理後,許多難懂的知識點都能迎刃而解。

原文出處#

  • 原書/iThome:https://ithelp.ithome.com.tw/articles/10217945