和你們分享有關CSS中層疊上下文
、層疊等級
、層疊順序
以及z-index
相關的一整套技術細節。html
以往,因爲本身使用z-index
的頻率不大,因此對這個CSS屬性存在比較片面的認識。一直認爲z-index
就是用來描述定義一個元素在屏幕Z軸
上的堆疊順序。z-index
值越大在Z軸
上就越靠上,也就是離屏幕觀察者越近。最後才發現這個認識存在很大的問題:前端
z-index
屬性值並非在任何元素上都有效果。它僅在定位元素(定義了position
屬性,且屬性值爲非static
值的元素)上有效果。Z軸
上的堆疊順序,不只僅是直接比較兩個元素的z-index
值的大小,這個堆疊順序實際由元素的層疊上下文、層疊等級共同決定。
要想徹底理解一個東西,首先要明白它是什麼,也就是它的定義。咱們先看看上面提到的層疊上下文
、層疊等級
、層疊順序
都是什麼?定義又太過抽象,後面會再用一個具象的比喻來讓你完全明白它們究竟是什麼,有什麼聯繫。web
層疊上下文(stacking context),是HTML中一個三維的概念。在CSS2.1規範中,每一個盒模型的位置是三維的,分別是平面畫布上的X軸
,Y軸
以及表示層疊的Z軸
。通常狀況下,元素在頁面上沿X軸Y軸
平鋪,咱們察覺不到它們在Z軸
上的層疊關係。而一旦元素髮生堆疊,這時就能發現某個元素可能覆蓋了另外一個元素或者被另外一個元素覆蓋。工具
若是一個元素含有層疊上下文,(也就是說它是層疊上下文元素),咱們能夠理解爲這個元素在Z軸
上就「高人一等」,最終表現就是它離屏幕觀察者更近。佈局
具象的比喻:你能夠把層疊上下文元素理解爲理解爲
該元素當了官,而其餘非層疊上下文元素則能夠理解爲普通羣衆。凡是「當了官的元素」就比普通元素等級要高,也就是說元素在
Z軸
上更靠上,更靠近觀察者。
那麼,層疊等級指的又是什麼?層疊等級(stacking level,叫「層疊級別」/「層疊水平」也行)學習
Z軸
上的上下順序。Z軸
上的上下順序。說到這,可能不少人疑問了,不論在層疊上下文中仍是在普通元素中,層疊等級都表示元素在Z軸
上的上下順序,那就直接說它描述定義了全部元素在Z軸
上的上下順序就OK啊!爲何要分開描述?開發工具
爲了說明緣由,先舉個栗子:測試
具象的比喻:咱們以前說到,處於層疊上下文中的元素,就像是元素當了官,等級天然比普通元素高。再想象一下,假設一個官員A是個省級領導,他下屬有一個祕書a-1,家裏有一個保姆a-2。另外一個官員B是一個縣級領導,他下屬有一個祕書b-1,家裏有一個保姆b-2。a-1和b-1雖然都是祕書,可是你想一個省級領導的祕書和一個縣級領導的祕書之間有可比性麼?甚至保姆a-2都要比祕書b-1的等級高得多。誰大誰小,誰高誰低一目瞭然,因此根本沒有比較的意義。只有在A下屬的a-一、a-2以及B下屬的b-一、b-2中相互比較大小高低纔有意義。
再類比回「層疊上下文」和「層疊等級」,就得出一個結論:flex
前面說了那麼多,知道了「層疊上下文」和「層疊等級」,其中還有一個最關鍵的問題:到底如何產生層疊上下文呢?如何讓一個元素變成層疊上下文元素呢?spa
其實,層疊上下文也基本上是有一些特定的CSS屬性建立的,通常有3種方法:
HTML
中的根元素<html></html>
自己j就具備層疊上下文,稱爲「根層疊上下文」。position
屬性爲非static
值並設置z-index
屬性爲具體數值,產生層疊上下文。至此,終於能夠上代碼了,咱們用代碼說話,來驗證上面的結論:
栗子1: 有兩個div,p.a、p.b被包裹在一個div裏,p.c被包裹在另外一個盒子裏,只爲.a、.b、.c設置position
和z-index
屬性
<style> div { position: relative; width: 100px; height: 100px; } p { position: absolute; font-size: 20px; width: 100px; height: 100px; } .a { background-color: blue; z-index: 1; } .b { background-color: green; z-index: 2; top: 20px; left: 20px; } .c { background-color: red; z-index: 3; top: -20px; left: 40px; } </style> <body> <div> <p class="a">a</p> <p class="b">b</p> </div> <div> <p class="c">c</p> </div> </body> web前端開發學習Q-q-u-n: 784783012 ,分享開發工具,零基礎,進階視頻教程,但願新手少走彎路
效果:
由於p.a、p.b、p.c三個的父元素div都沒有設置z-index
,因此不會產生層疊上下文,因此.a、.b、.c都處於由<html></html>
標籤產生的「根層疊上下文」中,屬於同一個層疊上下文,此時誰的z-index
值大,誰在上面。
栗子2: 有兩個div,p.a、p.b被包裹在一個div裏,p.c被包裹在另外一個盒子裏,同時爲兩個div和.a、.b、.c設置position
和z-index
屬性
<style> div { width: 100px; height: 100px; position: relative; } .box1 { z-index: 2; } .box2 { z-index: 1; } p { position: absolute; font-size: 20px; width: 100px; height: 100px; } .a { background-color: blue; z-index: 100; } .b { background-color: green; top: 20px; left: 20px; z-index: 200; } .c { background-color: red; top: -20px; left: 40px; z-index: 9999; } </style> <body> <div class="box1"> <p class="a">a</p> <p class="b">b</p> </div> <div class="box2"> <p class="c">c</p> </div> </body>
效果:
咱們發下,雖然p.c
元素的z-index
值爲9999,遠大於p.a
和p.b
的z-index
值,可是因爲p.a
、p.b
的父元素div.box1
產生的層疊上下文的z-index
的值爲2,p.c
的父元素div.box2
所產生的層疊上下文的z-index
值爲1,因此p.c
永遠在p.a
和p.b
下面。
同時,若是咱們只更改p.a
和p.b
的z-index
值,因爲這兩個元素都在父元素div.box1
產生的層疊上下文中,因此,誰的z-index
值大,誰在上面。
說完「層疊上下文」和「層疊等級」,咱們再來講說「層疊順序」。「層疊順序」(stacking order)表示元素髮生層疊時按照特定的順序規則在Z軸
上垂直顯示。因而可知,前面所說的「層疊上下文」和「層疊等級」是一種概念,而這裏的「層疊順序」是一種規則。
在不考慮CSS3的狀況下,當元素髮生層疊時,層疊順訊遵循上面途中的規則。 這裏值得注意的是:
background/border
"指的是層疊上下文元素的背景和邊框。inline/inline-block
元素的層疊順序要高於block
(塊級)/float
(浮動)元素。z-index: auto
和z-index: 0
在同一層級,但這兩個屬性值自己是有根本區別的。對於上面第2條,爲何inline/inline-block
元素的層疊順序要高於block
(塊級)/float
(浮動)元素?這個你們能夠思考一下! 其實很簡單,像border/background
屬於裝飾元素的屬性,浮動和塊級元素通常用來頁面佈局,而網頁設計之初最重要的就是文字內容,因此在發生層疊時會優先顯示文字內容,保證其不被覆蓋。
上面說了那麼多,可能你仍是有點懵。這麼多概念規則,來點最實際的,有沒有一個「套路」當遇到元素層疊時,能很清晰地判斷出他們誰在上誰在下呢?答案是——確定有啊!
一、首先先看要比較的兩個元素是否處於同一個層疊上下文中: 1.1若是是,誰的層疊等級大,誰在上面(怎麼判斷層疊等級大小呢?——看「層疊順序」圖)。 1.2若是兩個元素不在統一層疊上下文中,請先比較他們所處的層疊上下文的層疊等級。 二、當兩個元素層疊等級相同、層疊順序相同時,在DOM結構中後面的元素層疊等級在前面元素之上。
對於技術學習,代碼展現是最直觀最易懂的方式之一。話很少說,直接上代碼,咱們經過如下幾個「栗子」,來進一步驗證掌握上面的結論。
栗子3:
<style> .box1, .box2 { position: relative; z-index: auto; } .child1 { width: 200px; height: 100px; background: #168bf5; position: absolute; top: 0; left: 0; z-index: 2; } .child2 { width: 100px; height: 200px; background: #32c292; position: absolute; top: 0; left: 0; z-index: 1; } </style> </head> <body> <div class="box1"> <div class="child1"></div> </div> <div class="box2"> <div class="child2"></div> </div> </body>
效果:
說明:.box1/.box2
雖然設置了position: relative
,可是z-index: auto
的狀況下,這兩個div
仍是普通元素,並無產生層疊上下文。因此,child1/.child2
屬於<html></html>
元素的「根層疊上下文」中,此時,誰的z-index
值大,誰在上面。
栗子4:
對於栗子1中的CSS代碼,咱們只把.box1/.box2
的z-index
屬性值改成數值0
,其他不變。
.box1, .box2 { position: relative; z-index: 0; } ... web前端開發學習Q-q-u-n: 784783012 ,分享開發工具,零基礎,進階視頻教程,但願新手少走彎路
效果:
說明: 此時,咱們發現,僅僅修改了.box1/.box2
的z-index
屬性值改成數值0
,最終結果徹底相反。這時.child2
覆蓋在了.child1
上面。緣由是什麼呢?很簡單:由於設置z-index: 0
後,.box1/.box2
產生了各自的層疊上下文,這時候要比較.child1/.child2
的層疊關係徹底由父元素.box1/.box2
的層疊關係決定。可是.box1/.box2
的z-index
值都爲0
,都是塊級元素(因此它們的層疊等級,層疊順序是相同的),這種狀況下,在DOM
結構中後面的覆蓋前面的,因此.child2
就在上面。
CSS3中出現了不少新屬性,其中一些屬性對層疊上下文也產生了很大的影響。以下:
flex|inline-flex
,子元素z-index
屬性值不爲auto
的時候,子元素爲層疊上下文元素;opacity
屬性值不是1
;transform
屬性值不是none
;mix-blend-mode屬性值不是
normal`;filter
屬性值不是none
;isolation
屬性值是isolate
;will-change
指定的屬性值爲上面任意一個;-webkit-overflow-scrolling
屬性值設置爲touch
。CSS3中,元素屬性知足以上條件之一,就會產生層疊上下文。咱們用第1條來作一個簡單的解釋說明。
栗子5:
<style> .box { } .parent { width: 200px; height: 100px; background: #168bf5; /* 雖然設置了z-index,可是沒有設置position,z-index無效,.parent仍是普通元素,沒有產生層疊上下文 */ z-index: 1; } .child { width: 100px; height: 200px; background: #32d19c; position: relative; z-index: -1; } </style> </head> <body> <div class="box"> <div class="parent"> parent <div class="child">child</div> </div> </div> </body>
效果:
說明: 咱們發現,.child
被.parent
覆蓋了。按照「套路」來分析一下: 雖然.parent
設置了z-index
屬性值,可是沒有設置position
屬性,z-index
無效,因此沒有產生層疊上下文,.parent
仍是普通的塊級元素。此時,在層疊順序規則中,z-index
值小於0
的.child
會被普通的block
塊級元素.parent
覆蓋。
栗子6:
對於上面的栗子,咱們只修改.box的屬性,設置display: flex,其他屬性和DOM結構不變。
.box { display: flex; }
效果:
說明: 當給.box
設置display: flex
時,.parent
就變成層疊上下文元素,根據層疊順序規則,層疊上下文元素的background/border
的層疊等級小於z-index
值小於0
的元素的層疊等級,因此z-index
值爲-1
的.child
在.parent
上面。
下面的代碼,我會把最終頁面渲染的結果放在代碼以後,有興趣的「童鞋」能夠分析一下,各個元素的層疊等級,最後來肯定這些元素哪一個在上哪一個在下。
<style> .parent { width: 100px; height: 200px; background: #168bf5; position: absolute; top: 0; left: 0; z-index: 0; } .child1 { width: 100px; height: 200px; background: #32d19c; position: absolute; top: 20px; left: 20px; z-index: 1; } .child2 { width: 100px; height: 200px; background: #e4c950; position: absolute; top: 40px; left: 40px; z-index: -1; } .child2-1 { width: 100px; height: 200px; background: #e45050; position: absolute; top: 60px; left: 60px; z-index: 9999; } .child2-2 { width: 100px; height: 200px; background: #db68a7; position: absolute; top: 80px; left: 40px; z-index: -9999; } </style> </head> <body> <div class="parent"> parent <div class="child1">child1</div> <div class="child2"> child2 <div class="child2-1">child2-1</div> <div class="child2-2">child2-2</div> </div> </div> </body> web前端開發學習Q-q-u-n: 784783012 ,分享開發工具,零基礎,進階視頻教程,但願新手少走彎路
效果: