CSS堆疊上下文(The stacking context)

1. 堆疊順序

堆疊順序(stacking order):HTML 內元素發生層疊的時候的特定垂直順序,即元素在用戶視線方向上的順序。


一般而言,div 以內在層疊順序上對于視覺有影響的一般有以下幾個:

  • background
  • border
  • 塊級元素
  • 內聯元素
  • 浮動塊級元素
  • 定位塊級元素

接下來,我們一個一個來測試一下他們的堆疊順序。

1. 首先,測試一下 background 和 border 的堆疊順序。

在日常寫頁面中,很大可能是這樣的:

HTML
<body>
  <div class="parent"></div>
</body>
CSS
.parent{
  height:40px;
  border:10px solid rgba(255,0,0,1);
  background:#000;
}
image.png

一個 div 元素內有一個 background 和一個 border,它們兩者是分開的嗎?
現在,將該 div 的 border 顏色改為半透明

.parent{
  height:40px;
  border:10px solid rgba(255,0,0,0.4);
  background:#000;
}

image.png

從頁面效果,可以很明顯地看出來,border 的顏色并不是純種的紅色,而是紅色之中透著黑色。
顯而易見,border 之中的黑色就是 div 元素的background。
由上面可以推斷得出,border 的堆疊順序是比 background 要高的。即 border > background


2. 接下來,給 div 加一個內聯元素和一個塊級元素

HTML
<body>
  <div class="parent">
    <span>內聯元素</span>
    <div class="child"></div>
  </div>
</body>
CSS
.parent{
  height:150px;
  border:10px solid rgba(255,0,0,1);
  background:#000;
}
span{
  color:#fff;
}
.child{
  width:80px;
 height:50px;
 background:green;
}
顯示效果
image.png

從上圖可以看出來,內聯元素和塊級元素的堆疊順序都是大于 background 的,那么他們與 border 相比較呢?
想辦法把這兩個元素移動到與 border 相覆蓋,就可以知道他們的堆疊順序。
往兩個元素上分別加一個 margin-left:-10px;

CSS
.parent{
  height:150px;
  border:10px solid rgba(255,0,0,1);
  background:#000;
}
span{
  color:#fff;
  margin-left:-10px;
}
.child{
  width:80px;
 height:50px;
 background:green;
 margin-left:-10px;
}
顯示效果
image.png

可以知道,內聯元素和塊級元素的堆疊順序都大于 border 的堆疊順序。那么這兩者之間的堆疊順序呢?
再往塊級元素上加一個 margin-top:-10px;

CSS
.parent{
  height:150px;
  border:10px solid rgba(255,0,0,1);
  background:#000;
}
span{
  color:#fff;
  margin-left:-10px;
}
.child{
  width:80px;
 height:50px;
 background:green;
 margin-left:-10px;
  margin-top:-10px;
}
顯示效果

image.png

從上圖可以看到,綠色背景的塊級元素向上移動 10px,但是內聯元素依然在塊級元素上面,說明內聯元素的堆疊順序大于塊級元素的內聯順序,即 內聯元素 > 塊級元素 > border > background


3. 接下來該比較一下浮動元素了

先加一個浮動元素,背景色為藍色。

HTML
<body>
  <div class="parent">
    <span>內聯元素</span>
    <div class="child"></div>
    <div class="float"></div>
  </div>
</body>
CSS
.float{
  width:80px;
  height:50px;
  background:blue;
  float:left;
}
顯示效果
image.png

現在,先測試一次,藍色的浮動元素與目前已知的最高級的內聯元素哪個堆疊順序比較大。給浮動元素加一個margin-top:-60px;

.float{
  width:80px;
  height:50px;
  background:blue;
  float:left;
  margin-top: -60px;
}

image.png

由上圖可以知道,內聯元素在浮動元素上面,所以內聯元素的堆疊順序比浮動元素大,而浮動元素又在塊級元素上面,所以浮動元素的堆疊順序大于塊級元素。即 內聯元素 > 浮動元素 > 塊級元素 > border > background


4. 接下來是定位(position:relative;和position:absolute;)元素

依然是加一個定位元素

HTML
<body>
  <div class="parent">
    <span>內聯元素</span>
    <div class="child"></div>
    <div class="float"></div>
    <div class="relative"></div>
  </div>
</body>
CSS
.relative{
  width:70px;
  height:50px;
  background:yellow;
  position:relative;
}
顯示效果
image.png

依然是加margin-top:-50px;

.relative{
  width:70px;
  height:50px;
  background:yellow;
  position:relative;
  margin-top:-50px;
}
image.png

可以看到,position:relative; 的元素直接蓋住了目前已知最高等級的內聯元素,說明 position:relative; 的元素的堆疊順序比內聯元素的要大。
接下來看一下 position:absolute; 將上面 position:relative; 改為 position:absolute;

.relative{
  width:70px;
  height:50px;
  background:yellow;
  position:absolute;
  margin-top:-50px;
}
image.png

從圖片可以看出結果是一摸一樣的,說明 position:relative和 position:absolute; 有一樣的堆疊順序。
所以:定位元素 > 內聯元素 > 浮動元素 > 塊級元素 > border > background

5. 最后是 z-index 的影響

首先要知道,z-index 生效的前提是該元素是 position 屬性值是非static的元素,此時的 z-index為 auto。再添加一個元素,使它的 z-index生效

HTML
<body>
  <div class="parent">
    <span>內聯元素</span>
    <div class="child"></div>
    <div class="float"></div>
    <div class="relative"></div>
    <div class="z-index"></div>
  </div>
</body>
CSS
.z-index{
  width:90px;
  height:50px;
  background:orange;
  position:absolute;
  z-index:1;
}
顯示效果
image.png

接下來,繼續給一個margin-top:-40px;

.z-index{
  width:90px;
  height:50px;
  background:orange;
  position:absolute;
  z-index:1;
  margin-top: -40px;
}

image.png

可以看到橙色的加了 z-index 的元素蓋住了定位元素,說明: 正z-index > 定位元素 > 內聯元素 > 浮動元素 > 塊級元素 > border > background
現在測試一下負z-index,將z-index:1;改為 z-index:-1;

.z-index{
  width:90px;
  height:50px;
  background:orange;
  position:absolute;
  z-index:-1;
  margin-top:-40px;
}
image.png

可以看到,橙色元素完全被蓋住了。
修改一下margin,試著讓它顯示出來。

.z-index{
  width:90px;
  height:50px;
  background:orange;
  position:absolute;
  z-index:-1;
  margin-top:0px;
}
image.png

可以看到,即使不加margin負值,依然看不到。
設置margin-top:70px;

.z-index{
  width:90px;
  height:50px;
  background:orange;
  position:absolute;
  z-index:-1;
  margin-top:70px;
}
image.png

可以看到,橙色有一部分被背景蓋住了,說明:

正z-index > 浮動元素 > 內聯元素 > 浮動元素 > 塊級元素 > border > background > 負z-index

綜合上面所有內容,元素的堆疊順序就出來了。
就是下面這個:

正z-index > 浮動元素 > 內聯元素 > 浮動元素 > 塊級元素 > border > background > 負z-index

上面的順序,越大的離用戶越近。

2. 堆疊上下文

堆疊上下文:stacking context,類似與作用域,由不同的CSS屬性造成的一類具有相同特征的東西,并沒有特定的概念。堆疊上下文影響的是元素 CSS 屬性中的 z-index,父元素是否是堆疊上下文,對具有z-index屬性的子元素的堆疊順序有影響。

文檔中的層疊上下文由滿足以下任意一個條件的元素形成:

  • 根元素 (HTML),
  • z-index 值不為 "auto"的 絕對/相對定位,
  • 一個 z-index 值不為 "auto"的 flex 項目 (flex item),即:父元素 display: flex|inline-flex的元素
  • opacity 屬性值小于 1 的元素(參考 the specification for opacity),
  • transform 屬性值不為 "none"的元素,
  • mix-blend-mode 屬性值不為 "normal"的元素,
  • filter值不為“none”的元素,
  • perspective值不為“none”的元素,
  • isolation 屬性被設置為 "isolate"的元素,
  • position: fixed
  • 在 will-change 中指定了任意 CSS 屬性,即便你沒有直接指定這些屬性的值(參考 這篇文章)
  • -webkit-overflow-scrolling 屬性被設置 "touch"的元素

接下來看一下堆疊上下文對 z-index 的影響:
首先創建一個父元素的 div 作為容器,然后添加兩個子 div ,兩個子 div 里分別添加一個子 div

HTML
<body>
  <div class="parent">
    <div class="a relative">
      <div class="aaa">aaa</div>
    </div>
    <div class="b relative">
      <div class="bbb">bbb</div>
    </div>
  </div>
</body>

接下來,使用 CSS 添加樣式,此時頁面內有一個堆疊上下文=》html 元素

CSS
.parent{
  height:200px;
  border:10px solid red;
  background:black;
  padding:10px;
}

.a,.b{
  border:1px solid red;
  width:200px;
  height:100px;
  background:green;
}

.aaa,.bbb{
  background:yellow;
}

.relative{
  position:relative;
}
顯示效果
image.png

接下來給 bbb 添加一個 z-index:1;并使它移動到 aaa 的位置。

.bbb{
  z-index:1;
  margin-top:-90px;
}

image.png

可以看到 bbb 蓋住了 aaa ,因為 bbb 的 z-index:1; 比 aaa 默認的 z-index:auto;更靠近用戶。說明 在同一個堆疊上下文中,z-index大的比z-index小的更靠近用戶
接下來使 a 和 b 形成堆疊上下文

.a,.b{
  border:1px solid red;
  width:200px;
  height:100px;
  background:green;
  z-index:0;
}
image.png

頁面并沒有變化,那么這時候修改一下 aaa 和 bbb 的z-index 大小呢?將 aaa 的 z-index 改為2

.aaa{
  z-index:2;
}

image.png

頁面依然沒有變化,說明不同堆疊上下文中,z-index的大小不會影響到元素的堆疊順序,此時的堆疊順序與堆疊上下文所屬元素的堆疊順序有關。

接下來讓 parent 元素形成堆疊上下文,并給 a 和 b 一個負z-index

.parent{
  height:200px;
  border:10px solid red;
  background:black;
  padding:10px;
  position:relative;
  z-index:0;
}

.a,.b{
  border:1px solid red;
  width:200px;
  height:100px;
  background:green;
  
}

.aaa,.bbb{
  background:yellow;
}

.relative{
  position:relative;
  z-index:-1;
  margin-top:50px;
}

image.png

可以看到,a 和 b 蓋住了 border,說明堆疊上下文中,負z-index > border。可以看作是堆疊上下文將所有元素包裹了起來,不允許有比堆疊上下文低的堆疊順序。


3. 總結

  1. 普通塊級元素中,z軸元素的堆疊順序如下:
    正z-index > 內聯元素 > 浮動元素 > 塊級元素 > border > background >負z-index
  2. 堆疊上下文中,z軸元素的堆疊順序如下:
    正z-index > 內聯元素 > 浮動元素 > 塊級元素 > 負z-index > border > background
  3. z軸順序遵循兩個原則:
  • 誰大誰上
  • 大小一樣,后來居上

部分參考自:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。