CSS堆疊上下文(The stacking context)

1. 堆疊順序

堆疊順序(stacking order):HTML 內(nèi)元素發(fā)生層疊的時(shí)候的特定垂直順序,即元素在用戶(hù)視線(xiàn)方向上的順序。


一般而言,div 以?xún)?nèi)在層疊順序上對(duì)于視覺(jué)有影響的一般有以下幾個(gè):

  • background
  • border
  • 塊級(jí)元素
  • 內(nèi)聯(lián)元素
  • 浮動(dòng)塊級(jí)元素
  • 定位塊級(jí)元素

接下來(lái),我們一個(gè)一個(gè)來(lái)測(cè)試一下他們的堆疊順序。

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

在日常寫(xiě)頁(yè)面中,很大可能是這樣的:

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

一個(gè) div 元素內(nèi)有一個(gè) background 和一個(gè) border,它們兩者是分開(kāi)的嗎?
現(xiàn)在,將該 div 的 border 顏色改為半透明

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

image.png

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


2. 接下來(lái),給 div 加一個(gè)內(nèi)聯(lián)元素和一個(gè)塊級(jí)元素

HTML
<body>
  <div class="parent">
    <span>內(nèi)聯(lián)元素</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

從上圖可以看出來(lái),內(nèi)聯(lián)元素和塊級(jí)元素的堆疊順序都是大于 background 的,那么他們與 border 相比較呢?
想辦法把這兩個(gè)元素移動(dòng)到與 border 相覆蓋,就可以知道他們的堆疊順序。
往兩個(gè)元素上分別加一個(gè) 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

可以知道,內(nèi)聯(lián)元素和塊級(jí)元素的堆疊順序都大于 border 的堆疊順序。那么這兩者之間的堆疊順序呢?
再往塊級(jí)元素上加一個(gè) 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

從上圖可以看到,綠色背景的塊級(jí)元素向上移動(dòng) 10px,但是內(nèi)聯(lián)元素依然在塊級(jí)元素上面,說(shuō)明內(nèi)聯(lián)元素的堆疊順序大于塊級(jí)元素的內(nèi)聯(lián)順序,即 內(nèi)聯(lián)元素 > 塊級(jí)元素 > border > background。


3. 接下來(lái)該比較一下浮動(dòng)元素了

先加一個(gè)浮動(dòng)元素,背景色為藍(lán)色。

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

現(xiàn)在,先測(cè)試一次,藍(lán)色的浮動(dòng)元素與目前已知的最高級(jí)的內(nèi)聯(lián)元素哪個(gè)堆疊順序比較大。給浮動(dòng)元素加一個(gè)margin-top:-60px;

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

image.png

由上圖可以知道,內(nèi)聯(lián)元素在浮動(dòng)元素上面,所以?xún)?nèi)聯(lián)元素的堆疊順序比浮動(dòng)元素大,而浮動(dòng)元素又在塊級(jí)元素上面,所以浮動(dòng)元素的堆疊順序大于塊級(jí)元素。即 內(nèi)聯(lián)元素 > 浮動(dòng)元素 > 塊級(jí)元素 > border > background


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

依然是加一個(gè)定位元素

HTML
<body>
  <div class="parent">
    <span>內(nèi)聯(lián)元素</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; 的元素直接蓋住了目前已知最高等級(jí)的內(nèi)聯(lián)元素,說(shuō)明 position:relative; 的元素的堆疊順序比內(nèi)聯(lián)元素的要大。
接下來(lái)看一下 position:absolute; 將上面 position:relative; 改為 position:absolute;

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

從圖片可以看出結(jié)果是一摸一樣的,說(shuō)明 position:relative和 position:absolute; 有一樣的堆疊順序。
所以:定位元素 > 內(nèi)聯(lián)元素 > 浮動(dòng)元素 > 塊級(jí)元素 > border > background

5. 最后是 z-index 的影響

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

HTML
<body>
  <div class="parent">
    <span>內(nèi)聯(lián)元素</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

接下來(lái),繼續(xù)給一個(gè)margin-top:-40px;

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

image.png

可以看到橙色的加了 z-index 的元素蓋住了定位元素,說(shuō)明: 正z-index > 定位元素 > 內(nèi)聯(lián)元素 > 浮動(dòng)元素 > 塊級(jí)元素 > border > background
現(xiàn)在測(cè)試一下負(fù)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,試著讓它顯示出來(lái)。

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

可以看到,即使不加margin負(fù)值,依然看不到。
設(shè)置margin-top:70px;

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

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

正z-index > 浮動(dòng)元素 > 內(nèi)聯(lián)元素 > 浮動(dòng)元素 > 塊級(jí)元素 > border > background > 負(fù)z-index

綜合上面所有內(nèi)容,元素的堆疊順序就出來(lái)了。
就是下面這個(gè):

正z-index > 浮動(dòng)元素 > 內(nèi)聯(lián)元素 > 浮動(dòng)元素 > 塊級(jí)元素 > border > background > 負(fù)z-index

上面的順序,越大的離用戶(hù)越近。

2. 堆疊上下文

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

文檔中的層疊上下文由滿(mǎn)足以下任意一個(gè)條件的元素形成:

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

接下來(lái)看一下堆疊上下文對(duì) z-index 的影響:
首先創(chuàng)建一個(gè)父元素的 div 作為容器,然后添加兩個(gè)子 div ,兩個(gè)子 div 里分別添加一個(gè)子 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>

接下來(lái),使用 CSS 添加樣式,此時(shí)頁(yè)面內(nèi)有一個(gè)堆疊上下文=》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

接下來(lái)給 bbb 添加一個(gè) z-index:1;并使它移動(dòng)到 aaa 的位置。

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

image.png

可以看到 bbb 蓋住了 aaa ,因?yàn)?bbb 的 z-index:1; 比 aaa 默認(rèn)的 z-index:auto;更靠近用戶(hù)。說(shuō)明 在同一個(gè)堆疊上下文中,z-index大的比z-index小的更靠近用戶(hù)
接下來(lái)使 a 和 b 形成堆疊上下文

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

頁(yè)面并沒(méi)有變化,那么這時(shí)候修改一下 aaa 和 bbb 的z-index 大小呢?將 aaa 的 z-index 改為2

.aaa{
  z-index:2;
}

image.png

頁(yè)面依然沒(méi)有變化,說(shuō)明不同堆疊上下文中,z-index的大小不會(huì)影響到元素的堆疊順序,此時(shí)的堆疊順序與堆疊上下文所屬元素的堆疊順序有關(guān)。

接下來(lái)讓 parent 元素形成堆疊上下文,并給 a 和 b 一個(gè)負(fù)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,說(shuō)明堆疊上下文中,負(fù)z-index > border。可以看作是堆疊上下文將所有元素包裹了起來(lái),不允許有比堆疊上下文低的堆疊順序。


3. 總結(jié)

  1. 普通塊級(jí)元素中,z軸元素的堆疊順序如下:
    正z-index > 內(nèi)聯(lián)元素 > 浮動(dòng)元素 > 塊級(jí)元素 > border > background >負(fù)z-index
  2. 堆疊上下文中,z軸元素的堆疊順序如下:
    正z-index > 內(nèi)聯(lián)元素 > 浮動(dòng)元素 > 塊級(jí)元素 > 負(fù)z-index > border > background
  3. z軸順序遵循兩個(gè)原則:
  • 誰(shuí)大誰(shuí)上
  • 大小一樣,后來(lái)居上

部分參考自:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容