CSS的「層」巒「疊」翠

前言

提起,z-index 你們腦海裏可能會馬上浮現這樣的知識點:「z-index 的值大小控制元素在 Z 軸上顯示的層級,z-index 越大顯示的層級越高(也就是在最上層,離觀察者越近),沒有指定的按照出現順序堆疊,此外 z-index 不能跨父元素比較。css

z-index 的使用彷佛就是這麼簡單,對吧?前端

咱們先看以下例 1:web

<div class="box box1">DIV#1,z-index爲2</div>
  <div class="box box2">DIV#2,z-index爲auto</div>
複製代碼

HTML 中有以下兩個元素,DIV#1 的 z-index 爲2,DIV#2 向右向上偏移。問:它們誰會顯示在上面?app

示例1 - 用法引導
示例1 - 用法引導

點擊 CSS的「層」巒「疊」翠 - 示例1 - 用法導引 進行編輯 (@verymuch) on CodePen. 編輯器

如上所示,z-index 爲 2 的元素並無顯示在第二個元素上面。這彷佛很奇怪,那究竟是爲何呢?wordpress

若是你也對此存在困擾,那就和我一塊兒往下看吧。筆者將逐步引導你們深刻理解 z-index 的用法。佈局

1、沒有使用 z-index 時,元素如何堆疊?

首先,咱們先了解下默認狀況下,元素的堆疊,即在沒有使用 z-index 時,元素是如何堆疊的。flex

若是沒有給任何元素指定 z-index,則元素按照以下順序進行堆疊(由下到上,由遠及近)。spa

  1. 根元素的背景和邊框
  2. 非定位的後代塊元素,按照在 HTML 中的出現順序進行堆疊
  3. 定位的後代塊元素,按照在 HTML 中的出現順序進行堆疊

注:定位的元素即爲 position 的值不是 static 的元素code

示例2 - 無z-index時的默認堆疊
示例2 - 無z-index時的默認堆疊

點擊 CSS的「層」巒「疊」翠 - 示例2 - 無z-index時的默認堆疊 進行編輯 (@verymuch) on CodePen.

如上例 2 所示,定位的元素(DIV#一、DIV#二、DIV#3 與 DIV#4)按照出現的順序堆疊。非定位的元素(DIV#5 與 DIV#6)雖然出如今後面,可是會被定位的元素遮蓋,不過它們自己是按照出現順序堆疊的。

注意,當使用order屬性改變flex元素子元素的出現順序時,對於堆疊規則也有一樣的影響。

以下例 3 所示,當將 DIV#2 的 order 改成-1 後,它出現的位置爲第一個,其堆疊順序也被 DIV#1 所遮蓋。

示例3 - flex中order對出現順序的影響
示例3 - flex中order對出現順序的影響

點擊 CSS的「層」巒「疊」翠 - 示例3 - flex中order對出現順序的影響 進行編輯 (@verymuch) on CodePen.

2、浮動塊默認如何堆疊

若是存在浮動塊,浮動塊的堆疊順序會介於無定位元素和定位元素之間。即:

  1. 根元素的背景和邊框
  2. 非定位的後代塊元素,按照在 HTML 中的出現順序進行堆疊
  3. 浮動塊
  4. 定位的後代塊元素,按照在 HTML 中的出現順序進行堆疊

咱們稍微修改下示例 2 中的代碼,將 DIV#1 和 DIV#3 改成浮動元素。能夠看到以下例 4 所示,浮動元素的堆疊順序高於非定位元素,低於定位元素。

示例4 - 浮動塊的堆疊
示例4 - 浮動塊的堆疊

點擊 CSS的「層」巒「疊」翠 - 示例4 - 浮動塊的堆疊 進行編輯 (@verymuch) on CodePen.

此外,還有一點小改動,不知道你有沒有注意到,咱們將非定位元素中的文本內容改成了左對齊,但其內容並無被浮動元素覆蓋。這實際上是浮動元素的標準效果——環繞效果。這一行爲也能夠列爲堆疊順序之一。順序以下:

  1. 根元素的背景和邊框
  2. 非定位的後代塊元素,按照在 HTML 中的出現順序進行堆疊
  3. 浮動塊
  4. 非定位元素的後代行內元素
  5. 定位的後代塊元素,按照在 HTML 中的出現順序進行堆疊

爲了讓你們清晰的理解上面所說的非定位元素的後代行內元素。你們能夠看下例 5。DIV#1 爲浮動元素,因此其層級高於在其後出現的 DIV#2。此時 DIV#1 向右偏移,能夠看見 DIV#2 中的行內文字元素(能夠爲純文字節點)層級高於 DIV#1。

示例5 - 非定位元素的後代行內元素
示例5 - 非定位元素的後代行內元素

點擊 CSS的「層」巒「疊」翠 - 示例5 - 非定位元素的後代行內元素 進行編輯 (@verymuch) on CodePen.

3、使用 z-index 自定義堆疊順序

以上是 CSS 中對於各種元素的默認排序,那咱們可否自定義排序呢?答案顯然是確定的。使用 z-index 能夠自定義堆疊順序。

z-index 的值能夠爲整數(正數、負數、0 都可)。使用方法很簡單。

須要注意如下三點:

  1. 未指定 z-index,默認爲 auto
  2. 若是 z-index 相同,則按照默認規則比較
  3. z-index 只能用於定位了的元素(暫時這麼說,下文會追加解釋)。 這也解釋了本文開頭的例 1 爲何不生效了。由於 z-index 對普通元素沒有效果。

以下例 6,咱們修改了例 2 中元素的 z-index。

咱們會發現 DIV#5 和 DIV#6 並不受 z-index 的影響。主要體如今兩個方面,首先 DIV#5 的 z-index 大於 DIV#6,可是顯示卻低於#DIV#6;其次是 DIV#5 的 z-index 小於 DIV#4,可是仍顯示在其上面。

而對於定位的元素,z-index 對其有影響,堆疊順序與數字大小符合。

示例6 - 使用z-index自定義堆疊順序
示例6 - 使用z-index自定義堆疊順序

點擊 CSS的「層」巒「疊」翠 - 示例6 - 使用z-index自定義堆疊順序 進行編輯 (@verymuch) on CodePen.

好了,相信經過上述內容,你們對於 z-index 應該有了必定的瞭解,可是以上僅僅是基本知識,關於堆疊遠遠沒有這麼簡單。

想要完全瞭解 z-index,咱們還要了解一下 CSS 堆疊的一個重要概念————堆疊上下文。

4、堆疊上下文

堆疊上下文是 HTML 中的三維概念,它抽象出了一個 z 軸,z 軸垂直於顯示器,指向用戶(假設用戶面朝顯示區域)。

在前面的內容中,之因此有些元素的渲染順序會受到 z-index 影響,是由於它們都由於某種緣由產生了一個堆疊上下文,而不只僅是上文提到的定位的元素。

那麼到底什麼狀況下會產生堆疊上下文呢?其實堆疊上下文的生成主要受到元素的屬性所影響。

若是任何一個元素知足一下條件之一,就會生成一個堆疊上下文。

  1. 文檔的根元素(HTML)默認爲一個堆疊上下文
  2. position值爲"absolute"或"relative",且 z-index 指定了除了 auto 之外值的元素
  3. position值爲"fixed"或"sticky"
  4. 彈性佈局的子元素,且 z-index 指定了除了 auto 之外值的元素
  5. opacity的值小於的元素
  6. mix-blend-mode的值不是 normal的元素
  7. 如下屬性值不爲"none"的元素
    • transform
    • filter
    • perspective
    • clip-path
    • mask / mask-image / mask-border
  8. isolation值爲"isolate"的元素
  9. -webkit-overflow-scrolling值爲"touch"的元素
  10. will-change指定了除初始值之外的任何屬性的元素
  11. contain值爲"layout"/"paint"及含義其中之一的組合值的元素

如上所述,有 11 種狀況會生成堆疊上下文,對於堆疊上下文能夠經過 z-index 指定其堆疊的順序(注意這裏不是上面說的只對定位元素生效了)。

對於堆疊上下文咱們須要知道如下幾點:

  1. 在每一個堆疊上下文內部,子元素的堆疊規則遵循上面所講的基本規則。
  2. 堆疊上下文能夠包含在其餘堆疊上下文內部,它們會建立一個堆疊上下文層級結構。
  3. 堆疊上下文的層級結構與 HTML 的元素不一樣,由於對於沒有建立堆疊上下文的元素會被父元素同化。 堆疊上下文的層級只包括建立了堆疊上下文的元素
  4. 堆疊上下文獨立於其兄弟元素,在處理自身內部堆疊時,只考慮其後代元素。內部堆疊完成後,將當前堆疊上下文當成一個總體,考慮在父堆疊上下文中的堆疊順序。通俗的說, 子堆疊上下文的 z-index 值只在父堆疊上下文中有意義。

注意,第四條和文章開頭提到的「z-index 不能跨父元素比較」是不等價的,由於其限制了必須是堆疊上下文。

針對這幾點,咱們看一下例 7。你們能夠先看一下是否理解。而後咱們再講解一下。

示例7 - 存在多級堆疊上下文時,元素的堆疊
示例7 - 存在多級堆疊上下文時,元素的堆疊

點擊 CSS的「層」巒「疊」翠 - 示例7 - 存在多級堆疊上下文時,元素的堆疊 進行編輯 (@verymuch) on CodePen.

示例 7 中,堆疊上下文的層級結構以下:

  • root
    • DIV#1
    • DIV#2
      • DIV#4
      • DIV#5
      • DIV#6
    • DIV#3
    • DIV#8

其中 DIV#4, DIV#5, DIV#6 是 DIV#2 的子元素,可見其堆疊順序被限制在 DIV#2 中,z-index 的值只在 DIV#2 內部有效,而後 DIV#2 又做爲一個總體與 DIV#1,DIV#3 按照上述規則進行堆疊。

DIV#7 被根元素同化,DIV#8 與 DIV#1, DIV#2, DIV#3 按照上述規則進行堆疊。在其三之上。

其實有個小方法可以幫助你們更好地判斷如何堆疊,那就是把堆疊上下文的層級結構類比爲版本號。以下:

  • root
    • DIV#1 (V3)
    • DIV#2 (V2)
      • DIV#4 (V2.1)
      • DIV#5 (V2.3)
      • DIV#6 (V2.4)
    • DIV#3 (V1)
    • DIV#8 (V4)

如上,類比成版本號以後,咱們就能很方便的判斷出誰上誰下啦。

5、注意事項

1. z-index: 0z-index: auto並不相同。

一般狀況下,相鄰的兩個元素,若是其 z-index 值分別爲0auto,看上去沒什麼區別的。以下例 8 所示。

DIV#1 的 z-index 值爲 0,其堆疊順序並無高於 DIV#2,而是和出現順序相同。

示例8 - zindex: 0 和 auto 的區別
示例8 - zindex: 0 和 auto 的區別

點擊 CSS的「層」巒「疊」翠 - 示例8 - zindex: 0 和 auto 的區別 進行編輯 (@verymuch) on CodePen.

可是實際上,這兩種狀況並不相同。上面提到,當元素「position值爲"absolute"或"relative",且 z-index 指定了除了 auto 之外值」時,元素會產生一個堆疊上下文,雖然元素自己堆疊順序沒有影響,可是其子元素的堆疊順序會有影響。以下例 9 所示。

由於 DIV#1 的 z-index 值不爲 auto,其產生了堆疊上下文,因此其子元素被限制在其內部,低於 DIV#2(若是 z-index 是 auto 的話,DIV#3 會高與 DIV#2)。

示例9 - zindex: 0 和 auto 的區別(2)
示例9 - zindex: 0 和 auto 的區別(2)

點擊 CSS的「層」巒「疊」翠 - 示例9 - zindex: 0 和 auto 的區別(2) 進行編輯 (@verymuch) on CodePen.

2. 不要濫用z-index,將堆疊上下文的層級結構打平

筆者之因此這樣建議,是由於當堆疊上下文的層級結構比較複雜時,簡單的修改某個元素的 z-index 或者其餘屬性,會致使一些沒法預知的影響。

以下例時所示,DIV#2 是 DIV#1 的子元素,DIV#4 是 DIV#3 的子元素,DIV#1 和 DIV#3 不是堆疊上下文,則 DIV#2 與 DIV#4 的堆疊順序與它們的 z-index 值對應。

示例10 - zindex形成的影響
示例10 - zindex形成的影響

點擊 CSS的「層」巒「疊」翠 - 示例10 - zindex形成的影響 進行編輯 (@verymuch) on CodePen.

但若是咱們在某些時候須要調整 DIV#3 的 z-index,如將其調整成z-index: 4;,那麼結果就徹底不同了。以下例 11 所示,DIV#4 高於 DIV#2 了。

示例11 - zindex形成的影響(2)
示例11 - zindex形成的影響(2)

See the Pen CSS的「層」巒「疊」翠 - 示例11 - zindex形成的影響(2) by verymuch (@verymuch) on CodePen.

因此筆者建議,你們必定要慎用,基於對堆疊上下文的理解基礎上,把握好頁面中堆疊上下文的層級結構,儘可能保持比較淺的層級結構,最好能與 HTML 層級結構一致,保證本身可以時刻知道如何進行修改與調整。

總結

以上,筆者從元素的默認堆疊順序,講到了堆疊上下文的生成。對上述內容瞭解以後,就可以很好地應對開發中所遇到的層級問題了。不過仍是建議你們在開發前,提早規劃好 z-index 的使用。避免最後本身沒法掌控。

參考文獻

  1. 深刻理解 CSS 中的層疊上下文和層疊順序
  2. Understanding CSS z-index

若是你喜歡,歡迎掃碼關注個人公衆號,我會按期陪讀,並分享一些其餘的前端知識。

相關文章
相關標籤/搜索