首先,先破題這篇文章部分內容來自 What No One Told You About Z-Index – Philip Walton 的啟發

本來是想紀錄 position: sticky 的用法,但看了一下我過去的在 position 的文章中,其實少紀錄了 z-indexstacking context 的概念,因此來補坑一下 XD(謎之音:其實是覺得複雜懶得寫 QQ)

有趣的問題

首先我們來看看一個身為前端工程師應該會遇到的日常,我們有三個 position:absolute 的 div 分別為 Red(z-index)/ Green / Blue 的色塊

程式碼與實際畫面可參考 JSFiddle 範例

問題:如何在不違反以下條件之下,將三個色塊的顯示順序更改為下圖的結果?

  1. 不能更改任何的 HTML code
  2. 不能 新增 / 移除更新 任何的 z-index
  3. 不能 新增 / 移除更新 任何的 position

⚠️ 在看程式碼的 CSS 之前,你可以嘗試自己在 JSFiddle 範例 中修改看看

預期結果如下:

解法:

我們只需要在 CSS 中為 div 加上以下程式碼即可

div {
  transform: translate(0%);
}

如果對於 z-index 的運作不是這麼熟的話,現在的你

有句話是這麼說的:

沒有 z-index: 999999; 解決不了的事,如果有的話,就 z-index: 2147483647
血淚史:身為廣告業的蓋版廣告開發者覺得兩手一攤

https://z3388638.medium.com/z-index-%E8%88%87-stacking-context-4d8312991954

此時你可以嘗試把 Red / Greenz-index 設定為 2147483647,你會發現設定任何值都蓋不過 Blue ,這似乎和 MDN 文件 說好的不一樣

The z-index CSS property sets the z-order of a positioned element and its descendants or flex items. Overlapping elements with a larger z-index cover those with a smaller one.

https://developer.mozilla.org/en-US/docs/Web/CSS/z-index

如果 position 不是 static(預設) 情況下,應該預期越大的 z-index 應該會蓋過 z-index 小的,如果沒設定的話,預設為 0

了解 z-index 作用的前提

翻翻 CSS2.2 spec 可以發現

An element is said to be positioned if its ‘position’ property has a value other than ‘static’. Positioned elements generate positioned boxes.

根據一個元素的 position 不同,我們將元素可以分為

  1. positioned box
    position 設定為 static 以外
  2. normal box
    position 為 static

接下來我們回頭看看 z-indexMDN 下方補充:

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

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

你會看到 z-index 的數值提到一個前提,在當前的 stacking context 的 stack level 設定 z 軸的順序,並且並且值越大的會覆蓋值越小的。(可以想像 z 值越大代表距離使用者螢幕越貼近,反之則越遠)

那所謂的 stacking context 是什麼?

你可以想像網頁上除了二維空間以外,還有一個第三維的 z 軸,在 z 軸上的值也就是所謂的 z-index。所有的元素在這個空間中,除了二維的排序外,還會根據 z 軸有一定的排序,我們稱這個空間為 stacking context

在一個頁面上,我們可以有許多的 stacking context,而不同的 stacking context 就像是所處空間不同,其下的子元素自然無法參照 z-index 值大小來決定一個元素在 z 軸的距離。

參考 MDN 文件 詳細的內容,產生 stacking context 有許多情境,簡單列在以下

  • Root element of the document (<html>)
  • Element with a position value absolute or relative and z-index value other than auto.
  • Element with a position value fixed or sticky (sticky for all mobile browsers, but not older desktop browsers).
  • Element that is a child of a flex container, with z-index value other than auto.
  • Element that is a child of a grid container, with z-index value other than auto.
  • Element with an opacity value less than 1 (See the specification for opacity).
  • Element with a mix-blend-mode value other than normal.
  • Element with any of the following properties with value other than none:
  • Element with an isolation value isolate.
  • Element with a will-change value specifying any property that would create a stacking context on non-initial value.
  • Element with a contain value of layout, or paint, or a composite value that includes either of them (i.e. contain: strictcontain: content).

以上落落長的許多 CSS 屬性會讓你可以建立一個新的 stacking context

像是以下的四個元素因為符合上面的規則,會產生四個不同的 stacking context

https://www.kabisa.nl/tech/how-the-css-stacking-context-works/

如果你讀到這裡,還是好奇為什麼上面的 transform 是否真的有產生 stacking context,可以使用 Chrome extensionFirefox extension 搭配 devtool,查看頁面上有哪些 stacking context


如果以後有前端工程師告訴你, z-index 就是越大蓋掉越小的,那接下來你一定要問他:

你知道什麼是 stacking context 嗎?

參考資料:

1 Comment

Leave a Reply