CSS進階(15)—— CSS世界的層疊規則(上)
說到CSS世界的層疊規則,很多人會想到z-index,翻譯成中文,叫做"z軸的順序"。事實上,拋開z-index只有在部分元素中(如定位元素)生效的條件,任何“元素”都無需藉助z-index的支援會有自己的層疊規則,這個層疊順序是基於z軸的。這裡我們需要了解一個概念,儘管我們平時看到的電腦螢幕是“二維”的平面,但事實上CSS世界的概念是“三維”的,他和我們人所在的世界一樣,經過任意一點可以有三條互相垂直的直線,當然這是三維空間的概念,和本文並無多大關係。
既然都是三維世界的層疊關係,那我們以自己的世界為例,來談談05年春晚的一個節目——千手觀音。
千手觀音這個節目很好的展現了三維世界的層疊關係與所展現的“視覺效果”。以圖片平面為xy平面,視覺上呈現了排在第一個的人的完整影象,已第一個人為準,排在他後面的人,構成了三維世界的z軸,由於後面的人在xy平面上的“大部分”影象都被遮擋,只能看到由於角度不同而呈現出來的手臂,因此最終在"xy"平面上呈現出千手觀音的效果。(三維世界的座標軸如下所示,我不敢在上圖中亂塗亂畫,我怕文字獄)
通過上面這個例子,我們需要明白一條CSS三維世界的第一準則:永遠不會有兩個在z軸上重合的“元素”!
1.什麼是層疊上下文
在理解CSS世界的層疊規則之前,我們必須要了解兩個關鍵詞——層疊上下文和層疊水平。本章的前面兩個小節就單獨來講一講這兩個關鍵詞。首先,什麼是層疊上下文?這是HTML中的一個官方的三維概念,這個說法聽起來有點像之前提到過的“塊狀格式化上下文”(BFC),這裡我們複習一下塊狀格式化上下文做了一件什麼事情,就是聲明瞭xxx屬性的元素他一不小心擁有了xxx特性。放在這裡也是同理,在CSS世界中,只要當前元素擁有了某些屬性(如position:relative;定位加上z-index不為auto),就會使得當前元素被“層疊上下文”。那麼這個被“層疊上下文”會使當前元素擁有什麼特性呢?
在講BFC的時候,我們提到了一個結界的概念,放在這裡,也依然適用,擁有層疊上下文特性的元素會生成一個“層疊結界”,這個“層疊結界”內部的所有元素會永遠的被束縛在某一段z軸空間內部,且永遠不能打破這個外層的“層疊結界”。這也就是為什麼有時候我們的子元素設定了z-index:9999仍然可能會被其他元素覆蓋,這很有可能是他的父元素不爭氣,排在了覆蓋物的後面導致的。如下例所示:
<div class="box1">我是配角</div> <div class="box2"> <div class="son">我才是主角,我被父元素的層疊上下文束縛了</div> </div> <style> .box1{ position: absolute; z-index: 1; width: 200px; height: 200px; background: yellow; opacity: 0.7; } .box2{ width: 400px; height: 300px; position: absolute; z-index: 0; background: green; text-align: right; } .box2>.son{ position: relative; z-index: 9999; } </style>
2.什麼是層疊水平
在本文中,我提出了一個概念——CSS世界中任何兩個“元素”不會在z軸上重合,由於不是所有元素需要被“CSS層疊上下文”,但所有的元素都需要有個z軸上的顯示順序,因此對於這些沒有被“層疊上下文”的元素如何顯示的問題就需要層疊水平的幫忙了。事實上,我們需要明確一個概念,就是所有的元素都擁有層疊水平,這是一個預設的“計算值”,但由於在聲明瞭層疊上下文後,這個計算值可以忽略不計,因此通常我們只在同一個層疊上下文中考慮層疊水平的問題。
說了這麼多,你可能仍然不能明白層疊水平是個什麼東西,這裡我們就用個例子來說明一下。
<div id="father">
<span id="son1">我是大兒子</span>
<span id="son2">我是二兒子</span>
</div>
在上例中,我們的父容器裡面有兩個span標籤,這兩個span標籤並不會產生所謂的“重疊”,但他們其實並沒有處在同一個z座標中,而且可以肯定的是,二兒子的顯示順序要優於大兒子,這是由普通元素的預設層疊水平決定的,至於為什麼是二兒子在大兒子上面,後面會詳細說到。
3.理解元素層疊順序的兩大法則
在理解了層疊上下文和層疊水平的概念後,我們可以來好好聊一聊CSS世界的顯示規則了,也就是本節要說的層疊順序。由於所有元素都自帶層疊規則,因此CSS制定了一套詳細的標準來規範元素在z軸上的顯示順序。如下圖所示:
可以看到,在每一個層疊上下文的結界中,任何內部元素的層級都要高於backgroud/border,因此background/border組成了層疊上下文的“地板”,而層疊上下文的“天花板”取決於內部元素的z-index:正值的大小(理論上是這樣)。
在這個層疊順序表中,我們可以注意到,在層疊上下文結界中,預設層級最高的是inline/inline-block元素,層級最低的永遠是background和border,預設層級居中的是一些佈局用的盒子,這也符合CSS設計的標準,以圖文展示為主,其次是佈局,最次兒的就是裝飾性的background和border屬性了。
除了上面提到的CSS2.1的標準,作者在CSS層疊領域總結了兩條黃金準則,在元素髮生層疊的時候,其覆蓋關係遵循下面兩條準則:
(1)誰大誰上:當具有明顯的層疊水平標識的時候,如生效的z-index屬性值,在同一個層疊上下文結界餒,層疊水平值大的那一個覆蓋小的那一個。
(2)後來居上:當元素層疊水平一致的時候,在DOM流中處於後面的元素會覆蓋前面的元素。
結合這兩條準則,就可以解釋任何元素髮生重疊時的顯示順序的問題了。
4.本章例項
在本章中我們瞭解了很多CSS世界中層疊規則的概念,下面我們需要結合上面三個小節的概念做一個綜合性的測試,主要是為了驗證CSS2.1的標準在谷歌瀏覽器下的表現是否依舊穩定。
第一個測試驗證:inline>float>block>background
在進行測試的時候,需要用到margin負邊距使得元素重疊,測試程式碼如下:
<!-- 綜合測試1 -->
<div class="father">
<span class="inline">inline元素</span>
<div class="float"></div>
<div class="block"></div>
</div>
<style>
.father{
position: relative;
background: rgb(255,255,0);
}
.block{
background: rgb(255, 0, 0);
width: 100px;
height: 120px;
}
.float{
float: left;
background: rgb(0,255,255);
width: 100px;
height: 100px;
margin-left: 50px;
}
.inline{
margin-left: -100px;
background: rgb(0,255,0);
}
</style>
結果表明inline>float>block>background的結論成立。
第二個測試驗證:z-index正值>z-index:0約等於z-index:auto>z-index負值
<!-- 綜合測試2 -->
<div class="father">
<div class="zIndex-1">負的z-index</div>
<div class="zIndexAuto">z-index:auto</div>
<div class="zIndex0">z-index:0</div>
<div class="zIndex1">正z-index</div>
</div>
<style>
.father{
position: relative;
background: rgb(255,255,0);
}
.zIndex-1{
position: absolute;
width: 100px;
height: 200px;
background: rgb(255,0,0);
left: 0;
top: 0px;
z-index: -1;
}
.zIndex0{
position: absolute;
width: 100px;
height: 100px;
background: rgb(0,255,0);
left: 0;
top: 100px;
z-index: 0;
}
.zIndexAuto{
position: absolute;
width: 100px;
height: 150px;
background: rgb(255,0,255);
left: 0;
top: 50px;
z-index: auto;
}
.zIndex1{
position: absolute;
width: 100px;
height: 50px;
background: rgb(0,255,255);
left: 0;
top: 150px;
z-index: 1;
}
</style>
在層疊水平上,z-index:auto和z-index:0的層疊順序是相同的,因此遵循後來居上的原則,但是z-index:0和z-index:auto在建立層疊上下文結界上有本質區別,這點在下一章節會詳細論述,感興趣的同學可以測試下上述所有元素混雜在一起的時候的層疊順序。本章主要就是些概念性的東西,為下一章深入瞭解做個準備。