css--深入由z-index引發的層疊上下文、層疊等級和層疊順序的思考

丶Serendipity丶發表於2021-12-29

前言

  在編寫css樣式程式碼的時候,我們經常會遇到z-index屬性的使用,我們可能只瞭解z-index能夠提高元素的層級,並不知道具體是怎麼實現的。本文就來總結一個由z-index 引發的層疊上下文和層疊順序相關知識點,有了這方面的瞭解,才能減少開發中遇到的bug,同時這也是面試中經常遇到的問題。

正文

  1、z-index 屬性

  通常情況下,html 頁面被認為是二維的,相當於只有 x 和 y 軸,因為文字、影像和其他元素被排列在頁面上而不重疊。這種情況下只有一個渲染程式,所有元素都知道其他元素所佔用的空間。z-index 屬性可讓你在渲染內容時調整物件分層的順序。z-index 屬性設定了一個定位元素及其後代元素或 flex 專案的 z-order。 當元素之間重疊的時候, z-index 較大的元素會覆蓋較小的元素在上層進行顯示。這樣似的html頁面變成了一個三維的空間。

  根據上面的理解,我們不難實現如下的效果:

   

 

 

 

 

 

  程式碼段1如下:我們只需要改變box盒子的z-index值的大小就會改變盒子的層疊順序。

    <style>
      div {
        width: 100px;
        height: 100px;
        font-size: 14px;
      }
      .box1 {
        position: absolute;
        top: 20px;
        left: 20px;
        background-color: red;
      }
      .box2 {
        position: absolute;
        top: 40px;
        left: 40px;
        background-color: yellow;
      }
      .box3 {
        position: absolute;
        top: 60px;
        left: 60px;
        background-color: green;
      }
    </style>
  <body>
    <div class="box1">box1</div>
    <div class="box2">box2</div>
    <div class="box3">box3</div>
  </body>

  初次看上面的程式碼,會發現 z-index 值越大在z軸上就越靠上,離瀏覽器螢幕越近。但是仔細思考,你會發現這裡存在很多疑惑:z-index是在任何元素上面都有效果嗎?難道z-index的值的大小直接影響到元素的層疊順序嗎?

  我們再來看下下面的程式碼段2:

    <style>
      .box1,.box2 {
        width: 100px;
        height: 100px;
        font-size: 14px;
        display: flex;
      }
      .box1 {
        position: absolute;
        top: 20px;
        left: 20px;
        background-color: red;
        z-index: 1;
      }
      .box2 {
        position: absolute;
        top: 40px;
        left: 40px;
        background-color: yellow;
      }
      .box1-item1 {
        width: 50px;
        height: 100px;
        border: 1px solid black;
      }
      .box1-item2 {
        width: 50px;
        height: 100px;
        border: 1px solid blue;
      }
      .box2-item1 {
        width: 50px;
        height: 100px;
        border: 1px solid black;
        z-index: 10;
      }
      .box2-item2 {
        width: 50px;
        height: 100px;
        border: 1px solid blue;
        z-index: 10;
      }
    </style>
  <body>
    <div class="box1">
      <div class="box1-item1">1</div>
      <div class="box1-item2">2</div>
    </div>
    <div class="box2">
      <div class="box2-item1">1</div>
      <div class="box2-item2">2</div>
    </div>
  </body>

  效果如下:

  產生這樣的效果,究竟是為什麼呢,明明box2-item1、box2-item2 的z-index屬性值更大,結果這兩個盒子會被覆蓋了呢。要想徹底知道其中的緣由,我們需要知道層疊上下、層疊等級、層疊順序這幾個概念。

  2、層疊上下文

  層疊上下文(Stacking context),是html頁面中的一個三維的概念,就是上面提到的 z-index 的產生,導致頁面有了z軸。預設a-index值為 aotu ,即z軸的0點處,同時可以設定z-index為正值和負值,表示該層疊上下文元素在z軸距離螢幕的遠近。

  3、層疊等級

  層疊等級(stacking level),在同一個層疊上下文中,它描述定義的是該層疊上下文中的層疊上下文元素在Z軸上的上下順序。在其他普通元素中,它描述定義的是這些普通元素在Z軸上的上下順序。只有在同一層疊上下文中,層疊等級才有意義,z-index優先順序最高。產生層疊上下文的條件:

  • 文件根元素(<html>);

  • position 值為 absolute(絕對定位)或  relative(相對定位)且 z-index 值不為 auto 的元素;

  • position 值為 fixed(固定定位)或 sticky(粘滯定位)的元素(沾滯定位適配所有移動裝置上的瀏覽器,但老的桌面瀏覽器不支援);

  • flex (flexbox (en-US)) 容器的子元素,且 z-index 值不為 auto

  • grid (grid) 容器的子元素,且 z-index 值不為 auto

  • opacity 屬性值小於 1 的元素(參見 the specification for opacity);

  • mix-blend-mode 屬性值不為 normal 的元素;

  • 以下任意屬性值不為 none 的元素:isolation 屬性值為 isolate 的元素;isolation 屬性值為 isolate 的元素;isolation屬性值為isolate的元素

    • transform
    • filter
    • perspective
    • clip-path
    • mask / mask-image / mask-border
  • -webkit-overflow-scrolling 屬性值為 touch 的元素;

  • isolation 屬性值為 isolate 的元素;
  • will-change 值設定了任一屬性而該屬性在 non-initial 值時會建立層疊上下文的元素(參考這篇文章);

  • contain 屬性值為 layoutpaint 或包含它們其中之一的合成值(比如 contain: strictcontain: content)的元素。

在層疊上下文中,子元素同樣也按照上面解釋的規則進行層疊。 重要的是,其子級層疊上下文的 z-index 值只在父級中才有意義。子級層疊上下文被自動視為父級層疊上下文的一個獨立單元。

  總結:

  • 層疊上下文可以包含在其他層疊上下文中,並且一起建立一個層疊上下文的層級。
  • 每個層疊上下文都完全獨立於它的兄弟元素:當處理層疊時只考慮子元素。
  • 每個層疊上下文都是自包含的:當一個元素的內容發生層疊後,該元素將被作為整體在父級層疊上下文中按順序進行層疊。

  4、層疊順序

  層疊順序”(stacking order)表示元素髮生層疊時按照特定的順序規則在Z軸上垂直顯示。由此可見,前面所說的“層疊上下文”和“層疊等級”是一種概念,而這裡的“層疊順序”是一種規則。

  5、分析程式碼段2

  程式碼段2中,因為box1 和 box2 盒子都設定了position :absolute,並且box1設定了z-index:1,使得根層級上下文中 box1層級等級高於box2,因此產生了下圖中左圖的效果。在box1 盒子中設定flex,而兩個子盒子box1-item1和box1-item2 預設的z-index值為auto,不會產生層級上下文關係,因此產生了下圖中中間的效果圖。在box2中設定了flex屬性,而裡面的 box2-item1 和 box2-item2 都設定了z-index值為10,產生了層級上下文,會高於box2 的Background 順序顯示,因此產生了下圖中有圖的效果。

 

寫在最後

  以上就是本文的全部內容,希望給讀者帶來些許的幫助和進步,方便的話點個關注,小白的成長之路會持續更新一些工作中常見的問題和技術點。

相關文章