了解 z-index 與 stacking context

Eason Lin
11 min readJan 9, 2022

--

前陣子在切版時遇到了較複雜的版型,花費了較多時間在規劃佈局及試錯,希望能藉此文章的整理好好了解 z-index 及 stacking context 的觀念。

為何了解 z-index 及 stacking context 非常重要

元素的重疊在切版中也許不會常常出現,甚至一些排版較單純的專案上是完全不用擔心這一塊的。

然而,如果對其完全沒有認識,很可能就會因為佈局的規劃出錯,導致須花費額外時間來補救。

不知道你是否有這樣經驗:

區塊 A 不知為何蓋過了區塊 B,不論把區塊 B 的 z-index 設到多大都無法讓區塊 B 蓋過區塊 A

藉著了解元素在不同狀況下的堆疊方式,可以有效地減少這類狀況的發生。

在沒有 z-index 時,元素如何決定先後順序?

當未設定 z-index 時,元素會這樣由下到上排序:

  1. 父層的框線與背景
  2. 子層未設定 position 的元素依出現順序
  3. 設定 position 的元素依出現順序

以下例子:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.wrapper {
padding: 20px;
display: inline-block;
background-color: rgb(199, 199, 0);
}
.box {
height: 200px;
border: 3px solid;
}
.non-positioned-1 {
width: 200px;
background-color: rgba(100, 100, 255, 0.8);
border-color: rgb(0, 0, 255);
}
.non-positioned-2 {
width: 300px;
background-color: rgba(100, 255, 100, 0.8);
border-color: rgb(0, 255, 0);
margin-top: -250px;
}
.positioned-1 {
width: 400px;
position: relative;
margin-top: -100px;
background-color: rgba(200, 50, 50, 0.8);
border-color: rgb(255, 0, 0);
}
</style>
</head>
<body>
<div class="wrapper">
<div class="box non-positioned-1">
<code>non-positioned-1</code>
</div>
<div class="box positioned-1">
<code>positioned-1</code>
</div>
<div class="box non-positioned-2">
<code>non-positioned-2</code>
</div>
</div>
</body>
</html>

父層的 wrapper 會在最下層,而 non-positioned-1 因為在 HTML 中先於同為子層的 non-position-2,因此被排在下方;positioned-1 儘管先於 non-positioned-2,因為其設定了 position: relative被排在最上方。

使用 z-index 改變上下排序

讓我們思考一個情境:如何讓藍綠紅由上到下排序呢?

以往在我的直覺上,我就會試著將 non-positioned-1z-index 設定為10 或是更大,但很顯然在此例中即使設定為 999 依然不會作用。

z-index 用於在 z 軸 (z-axis) 上的位置,預設為 auto,可給予整數作為值,其僅會作用於定位元素 (positioned element) ,因為元素在預設的定位上採用 position: static 來排序,因此 left, right, top, bottom 以及上述的 z-index 均無法作用。

在此例中,只要將三個盒子的 CSS 做一點調整,便能達成上述的情境:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.wrapper {
padding: 20px;
display: inline-block;
background-color: rgb(199, 199, 0);
}
.box {
height: 200px;
border: 3px solid;
}
.positioned-2 {
width: 200px;
background-color: rgba(100, 100, 255, 0.8);
border-color: rgb(0, 0, 255);
position: relative;
z-index: 2;
}
.positioned-3 {
width: 300px;
background-color: rgba(100, 255, 100, 0.8);
border-color: rgb(0, 255, 0);
margin-top: -250px;
position: relative;
z-index: 1;
}
.positioned-1 {
width: 400px;
position: relative;
margin-top: -100px;
background-color: rgba(200, 50, 50, 0.8);
border-color: rgb(255, 0, 0);
z-index: 0;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="box positioned-2">
<code>positioned-2</code>
</div>
<div class="box positioned-1">
<code>positioned-1</code>
</div>
<div class="box positioned-3">
<code>positioned-3</code>
</div>
</div>
</body>
</html>

堆疊環境 Stacking Context

堆疊環境(又稱層疊上下文)是指一組擁有共同父層的子元素一起在 z 軸上上下移動。

形成堆疊環境的條件有許多種。以上例來說,當我們將元素的 position 設定為 relative 且給予了 z-index 時,便各自形成了獨立的堆疊環境,其之間便可透過設定 z-index 決定其在 z 軸上的位置。如上例來看:

上面提到堆疊環境是指一組擁有共同父層的子元素一起在 z 軸上上下移動。擁有共同父層意味著什麼呢?讓我們在紅色背景父層的子層中加入一個橘色的子層 div:

// HTML
<div class="box positioned-1">
<code>positioned-1</code>
<div class="positioned-1-child"></div>
</div>
// CSS
.positioned-1-child {
width: 350px;
height: 150px;
background-color: orange;
position: absolute;
bottom: 0;
z-index: 999;
}

此時會發現,即使將子層的 z-index 設定為 999,依然無法讓橘色的盒子在堆疊上超過綠色或藍色的盒子,這是因為其父層的 z-index 為 0。

那要讓橘色的盒子移動到 Z 軸的最上方,可以怎麼做呢?

由於堆疊環境形成的條件之一是 positionrelative 且給予 z-index 時,只要將 position-1z-index 移除讓其變成預設的 auto,.position-1-child 便會自成一個堆疊環境,藉此達成目的:

      .positioned-1 {
width: 400px;
position: relative;
margin-top: -100px;
background-color: rgba(200, 50, 50, 0.8);
border-color: rgb(255, 0, 0);
/* z-index: 0; */
}
.positioned-1-child {
width: 350px;
height: 150px;
background-color: orange;
position: absolute;
bottom: 0;
z-index: 999;
}

--

--

Eason Lin
Eason Lin

Written by Eason Lin

Frontend Web Developer | Books

No responses yet