z-index的工作原理
HTML文檔中的元素卻是存在于三個維度之中。除了大家熟知的平面畫布中的x軸和y軸,還有控制第三維度的z軸。
像 margin , float , offset 這些屬性,控制著元素在x軸和y軸上的表現形式一樣。 z-index 這個屬性控制著元素在z軸上的表現形式。
z-index 屬性指定一個元素的堆疊順序。
堆疊順序是當前元素位于z軸上的值。數值越大表明元素的堆疊順序越高,越靠近屏幕。
如果未指定 z-index 的屬性,元素的堆疊順序基于它所在的文檔樹。默認情況下,文檔中后來聲明的元素具有更高的堆疊順序。
除了指定的 z-index,元素的堆疊順序是由大量的因素控制的。元素按照下面表格順序進行堆疊。
堆疊上下文(Stacking Contex)
當我們用 z-index 屬性指定元素的堆疊順序時,我們并不總是指定這個元素的堆疊順序相關于頁面內的其他元素。元素的堆疊順序只是相關于其堆疊上下文。
這可能會導致一些奇怪的情況,比如具有較大 z-index 的元素并不總是位于具有較低 z-index 元素的上方。
可以用下面的規則解釋堆疊上下文。
默認堆疊上下文是根元素
任何HTML文檔默認的堆疊上下文都是 元素。因此,除非創建新的堆疊上下文,默認情況下,元素的堆疊順序相關于頁面內的其他元素。
用 z-index 屬性建立一個新的堆疊上下文
我們是通過為一個元素的 z-index 屬性設置一個整數值來建立新的堆疊上下文。為達到預期效果,首先,設置該整數為當前元素的堆疊順序,其次,創建一個新的堆疊上下文。
新的堆疊上下文適用于該元素的任何子元素。子元素只和這個層堆疊上下文有關,和根堆疊上下文無關。
在下面的示例中,.foo 屬于堆疊上下文 1,而.bar 屬于堆疊上下文 2。
元素的堆疊順序不能高于 (或低于) 父元素的堆疊順序
當父元素的堆疊順序被設置的時候,這也意味著,它的子元素的堆疊順序不能高于或低于這一順序 (相對于父元素的堆疊上下文)。
在下面的示例中,即使 .bar 的 z-index 值高于 .baz,它依然顯示 .baz 下方。這是因為,在堆疊上下文1中,.bar 不能高于或低于堆疊順序1。
.foo { z-index: 1; }.
bar { z-index: 1000; }.
baz { z-index: 2; }
z-index適用范圍:它必須在被設定了 position 屬性元素上時才會生效,這意味著, z-index 只有在 position 設置為除 static 屬性上的元素上時,它才能更改層疊順序,在元素沒有設置任何 position 的情況下,z-index 將不會起任何作用。
z-index 僅適用于元素在其所屬的層疊上下文中的位置。
層疊上下文涉及到了 HTML 節點和它的所有子節點, HTML 元素位于層疊上下文的 root 級別,它可以被稱為根層疊。
文檔的默認層疊上下文(或"根層疊上下文")將 HTML 元素標記為其"根層疊",并且默認情況下,所有元素都屬于此根層疊上下文,但是,任何元素節點也可以是其"局部層疊上下文"中的根層疊。
你可以通過以下幾種方法將元素指定為新的局部層疊上下文的根層疊:
1.在設置了 position 為 absolute 或 relative 或其它任何除了 auto 屬性上設置 z-index
2.使用 position: fixed 或 position: sticky
3.元素上設置的 opacity 屬性值小于1
4.在元素上使用 transform 或 will-change
例:假設fatherA和fatherB處于同一個父盒子下,屬于兄弟結點
.fatherA {z-index:100} .fatherA sonA {z-index:100000}
.fatherB {z-index:200} .fatherB sonB {z-index:50}
我們可以看到,雖然sonA的z-index大于sonB。但是sonB層級比sonA高,覆蓋于sonA之上。這是因為fatherB的層級大于fatherA
這就說明,并不是z-index越大,離屏幕越近,而是必須同一個層疊上下文環境下(即以同一個元素作為根層疊,記住,能作為根層疊的,必須是設置了定位fixed\absolute\fixed的元素。如果當前父節點不是根層疊,那么就會默認想上找設置了定位的祖先結點,最后招不到才是html標簽)z-index越大,離屏幕越近
fatherA和fatherB是處于同一個層疊上下文環境,sonA和sonB是基于不同的層疊上下文環境,fatherA層級比fatherB高,那么fatherA的子集就一定會比fatherB的子集離屏幕更近(即使fatherA的子集設置了負數的z-index,也會比fatherB的子集高)
所以,我們判斷兩個元素誰的層級高,誰離屏幕更近,優先要看兩個元素,誰的層疊上下文環境層級高(即根層疊元素的層級);其次才是如果處于同一個層疊上下文環境,才會去比較二者的z-index
我們之前碰到的antd 的 modal會被其他組件覆蓋,實際上就是因為層疊上下文環境的影響,所以modal才會給出getContainer屬性