首先,先破題這篇文章部分內容來自 What No One Told You About Z-Index - Philip Walton 的啟發
本來是想紀錄 position: sticky
的用法,但看了一下我過去的在 position 的文章中,其實少紀錄了 z-index
與 stacking context
的概念,因此來補坑一下 XD(謎之音:其實是覺得複雜懶得寫 QQ)
有趣的問題
首先我們來看看一個身為前端工程師應該會遇到的日常,我們有三個 position:absolute
的 div 分別為 Red(z-index)/ Green / Blue 的色塊
程式碼與實際畫面可參考 JSFiddle 範例:
問題:如何在不違反以下條件之下,將三個色塊的顯示順序更改為下圖的結果?
- 不能更改任何的 HTML code
- 不能 新增 / 移除 或 更新 任何的
z-index
- 不能 新增 / 移除 或 更新 任何的
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 / Green 的 z-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.
如果 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
不同,我們將元素可以分為
-
positioned box
position
設定為 static 以外 -
normal box
position
為 static
接下來我們回頭看看 z-index
的 MDN 下方補充:
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.
你會看到 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
valueabsolute
orrelative
andz-index
value other thanauto
. -
Element with a
position
valuefixed
orsticky
(sticky for all mobile browsers, but not older desktop browsers). -
Element that is a child of a flex container, with
z-index
value other thanauto
. -
Element that is a child of a
grid
container, withz-index
value other thanauto
. -
Element with an
opacity
value less than1
(See the specification for opacity). -
Element with a
mix-blend-mode
value other thannormal
. -
Element with any of the following properties with value other than
none
: -
Element with an
isolation
valueisolate
. -
Element with a
will-change
value specifying any property that would create a stacking context on non-initial value. -
Element with a
contain
value oflayout
, orpaint
, or a composite value that includes either of them (i.e.contain: strict
,contain: content
).
以上落落長的許多 CSS 屬性會讓你可以建立一個新的 stacking context。
像是以下的四個元素因為符合上面的規則,會產生四個不同的 stacking context
如果你讀到這裡,還是好奇為什麼上面的 transform
是否真的有產生 stacking context,可以使用 Chrome extension 或 Firefox extension 搭配 devtool,查看頁面上有哪些 stacking context。
如果以後有前端工程師告訴你, z-index
就是越大蓋掉越小的,那接下來你一定要問他:
你知道什麼是 stacking context 嗎?