z-index為什么會不起作用


一、引子

見下圖,我們有onetwothree三個div

one嵌套了一個nesteddiv

nestedz-index等於100twoz-index只等於1

1-1 引子

但是nested卻仍然被two覆蓋。

Why?

別着急,我們慢慢剖析。

二、正常的元素順序

我們新建三個div

    <div>one</div>
    <div>two</div>
    <div>three</div>

頁面效果展示如下(代碼見附錄A):

2-1 正常的元素順序

正常的文檔流中,元素次序是跟元素在文檔中出現次序一致。

three出現最后,次序最高,覆蓋掉two

以此類推,two出現比one稍晚,所以覆蓋住one

三、positioned元素脫穎而出

當我們為two加上position:relative后(代碼見附錄B):

3-1 positioned元素

two脫穎而出,覆蓋住了onethree。

這是因為,瀏覽器先繪制non-positioned元素,再繪制positioned元素。

non-positioned元素position屬性值為默認值static,那么不為static的就是 positioned元素

四、都是positioned元素呢?

three也設置為position: relative的話(代碼見附錄C):

4-1 都是positioned元素

變回老樣子,positioned元素次序和在文檔出現次序一致。

想要讓two再次脫穎而出,那考慮z-index吧!

五、z-index的用處

當把two設置為z-index: 1后(代碼見附錄D):

5-1 把two的z-index設置為1

通過z-indextwo排到了前面。

Z”代表X-Y-Z笛卡爾坐標系中的深度。

z-index數值高的元素會排在z-index數字較低的元素之前。

使用z-index要注意兩個陷阱:

1. z-index只應用於positioned元素

2. 隱式地創建一個 層疊上下文(stack context)。

🚀 注意, 層疊上下文和BFC(Block Formatting Context)有所區別:

層疊上下文解決元素次序問題(一個元素是否排在另一個元素之前),而BFC解決文檔流和一個元素是否會被重疊。

六、 層疊上下文

當你在一個positioned元素上應用z-index,會隱式創建一個全新的 層疊上下文,這個元素同時成為了該 層疊上下文的根元素。

上節的two就是一個 層疊上下文的根元素。

z-index只控制當前層疊上下文的元素次序。

我們把onetwo設為position: relative,並且z-index都為1

並且在one中內嵌一個nesteddivnested設置(具體代碼見附錄E):

position: absolute;

z-index: 100;

結果展示的就是我們開頭所提到的:

6-1 z-index失效

雖然nested的z-index為100,可是還是被two所覆蓋。

這是因為,nestedtwo分別屬於兩個不同的層疊上下文。

z-index只控制自己當前層疊上下文的元素次序。

七、 深入層疊上下文

除了z-index會創建層疊上下文,opacity的值低於1也會創建,還有transformfilter也會,全部請詳見附錄F。

層疊上下文中元素的次序按照以下規則:

1. 層疊上下文的根元素

⬇️

2. z-index為負數的positioned元素

⬇️

3. Non-positioned元素

⬇️

4. z-indexauto的positioned元素

⬇️

5. z-index為正數的positioned元素

非必要不創建層疊上下文⚠️

在上一節的例子中,我們就感受到了,多個層疊上下文,一方面會造成混亂,另一方面會使我們受挫,達不到想要的效果。

八、 消除z-index魔術字的技巧

魔術字(magic number)指使用直接的數字字面量,這個值背后所代表的意思是隱藏着的,就像魔術一樣。

在之前的例子中,z-index為1,或者為100,都可以算魔術字。

消除魔術字,最好的方法是用變量規范起來。

比如,我們用變量去規范程序中各個z-index的值:

--z-loading-indicator: 100;
--z-nav-menu: 200;
--z-dropdown-menu: 300;
--z-modal-backdrop: 400;
--z-modal-body: 410;

最后

看到這里,恭喜你完成了z-index的學習 🎉🎉🎉

更多文章可以關注公眾號『鵬哥兒的Echo

生命不息,筆耕不輟

qrcode_for_gh_36929351504f_258.jpg

附錄A

HTML代碼

<body>
    <div class="box one">one</div>
    <div class="box two">two</div>
    <div class="box three">three</div>
</body>

CSS代碼

body {
    margin: 40px;
}

.box {
    display: inline-block;
    width: 200px;
    line-height: 200px;
    text-align: center;
    border: 2px solid black;
    background-color: #ea5;
    margin-left: -60px;
    vertical-align: top;
}

.one {
    margin-left: 0;
}

.two {
    margin-top: 30px;
}

.three {
    margin-top: 60px;
}

附錄B

HTML代碼

<body>
    <div class="box one">one</div>
    <!-- 增加一個class名 -->
    <div class="box two positioned">two</div>
    <div class="box three">three</div>
</body>

CSS代碼

body {
    margin: 40px;
}

.box {
    display: inline-block;
    width: 200px;
    line-height: 200px;
    text-align: center;
    border: 2px solid black;
    background-color: #ea5;
    margin-left: -60px;
    vertical-align: top;
}

.one {
    margin-left: 0;
}

.two {
    margin-top: 30px;
}

.three {
    margin-top: 60px;
}

/* 增加設置position值 */
.positioned {
    position: relative;
    background-color: #5ae;
}

附錄C

HTML代碼

<body>
    <div class="box one">one</div>
    <div class="box two positioned">two</div>
    <!-- three也設置為positioned -->
    <div class="box three positioned">three</div>
</body>

CSS代碼

body {
    margin: 40px;
}

.box {
    display: inline-block;
    width: 200px;
    line-height: 200px;
    text-align: center;
    border: 2px solid black;
    background-color: #ea5;
    margin-left: -60px;
    vertical-align: top;
}

.one {
    margin-left: 0;
}

.two {
    margin-top: 30px;
}

.three {
    margin-top: 60px;
}

/* CSS其實不變 */
.positioned {
    position: relative;
    background-color: #5ae;
}

附錄D

HTML代碼

<body>
    <div class="box one">one</div>
    <div class="box two positioned">two</div>
    <div class="box three positioned">three</div>
</body>

CSS代碼

body {
    margin: 40px;
}

.box {
    display: inline-block;
    width: 200px;
    line-height: 200px;
    text-align: center;
    border: 2px solid black;
    background-color: #ea5;
    margin-left: -60px;
    vertical-align: top;
}

.one {
    margin-left: 0;
}

.two {
    margin-top: 30px;
}

.three {
    margin-top: 60px;
}

.positioned {
    position: relative;
    background-color: #5ae;
}

/* 設置z-index */
.two{
    z-index: 1;
}

附錄E

HTML代碼

<body>
    <div class="box one positioned">
        one
        <div class="absolute">nested</div>
    </div>
    <div class="box two positioned">two</div>
    <div class="box three">three</div>
</body>

CSS代碼

body {
    margin: 40px;
}

.box {
    display: inline-block;
    width: 200px;
    line-height: 200px;
    text-align: center;
    border: 2px solid black;
    background-color: #ea5;
    margin-left: -60px;
    vertical-align: top;
}

.one {
    margin-left: 0;
}

.two {
    margin-top: 30px;
}

.three {
    margin-top: 60px;
}

.positioned {
    position: relative;
    background-color: #5ae;
    z-index: 1;
}

.absolute {
    position: absolute;
    top: 1em;
    right: 1em;
    height: 2em;
    background-color: #fff;
    border: 2px dashed #888;
    padding: 1em;
    line-height: initial;
    z-index: 100;
}

附錄F

滿足以下任意條件可創建層疊上下文[2]

  • 文檔根元素(<html>);
  • position屬性值為absoluterelative,並且z-index不為auto的元素;
  • position屬性值為fixedsticky的元素
  • flex容器的子元素,且z-index值不為auto
  • grid容器的子元素,且z-index值不為auto
  • opacity屬性值小於1的元素
  • mix-blend-mode屬性值不為normal的元素;
  • 以下任意屬性值不為none的元素
    • transform
    • filter
    • perspective
    • clip-path
    • mask / mask-image / mask-border
  • isolation屬性值為isolate的元素
  • -webkit-overflow-scrolling屬性值為touch的元素
  • 值設定了任一屬性而該屬性在 non-initial 值時會創建層疊上下文的元素(參考這篇文章[3]
  • contain屬性值為layoutpaint或包含它們其中之一的合成值,比如(contain: strictcontain: content)的元素

Reference

[1] CSS In Depth: 7.4 Stacking contexts and z-index

[2] 層疊上下文: https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context

[3] Everything You Need to Know About the CSS will-change Property: https://dev.opera.com/articles/css-will-change-property/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM