設(shè)計前端關(guān)于z-index的那些事兒
關(guān)于z-index的真正問題是,很少有人理解它到底是怎么用。其實(shí)它并不復(fù)雜,但是如果你從來沒有花一定時間去看具體的z-index相關(guān)文檔,那么你很可能會忽略一些重要的信息。
不相信我嗎?好吧,看看你能否解決下面這個問題:
問題:
在 接下來的HTML里 有三個<div>元素,并且每個<div>里包含一個<span>元素。每 個<span>被分別給定一個背景顏色:紅、綠、藍(lán)。每個<span>被放置到文檔的左上角附近,部分重疊著其他 的<span>元素,這樣你就可以看到哪些是被堆疊在前面。第一個<span>有一個z-index的值為1,而其他兩個沒有任 何z-index值。
以下就是這個HTML和它的基本CSS。
HTML代碼
1 2 3 4 5 6 7 8 9 |
<div> <span>Red</span> </div> <div> <span>Green</span> </div> <div> <span>Blue</span> </div> |
CSS代碼
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.red, .green, .blue { position: absolute; } .red { background: red; z-index: 1; } .green { background: green; } .blue { background: blue; } |
挑戰(zhàn):
嘗試使紅色<span>元素堆在藍(lán)色和綠色<span>的后面,不要打破以下規(guī)則:
- 不要以任何方式改變HTML標(biāo)記
- 不要添加/修改任何元素的z-index屬性
- 不要添加/修改任何元素的position屬性
如果你找到了答案,那么它應(yīng)該像下面這樣:
1 2 3 4 5 6 7 8 9 |
<div> <span>Red</span> </div> <div> <span>Green</span> </div> <div> <span>Blue</span> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
div:first-child { opacity: .99; } .red, .green, .blue { position: absolute; } .red { background: red; z-index: 1; } .green { background: green; } .blue { background: blue; } |
解決方案:
這個解決方法是在第一個<div>里(紅色<span>的父節(jié)點(diǎn))添加一個小于1的opacity屬性值。下面就是被添加的CSS的例子:
1 2 3 |
div:first-child { opacity: .99; } |
如果你現(xiàn)在很震驚,但是仍然百思不得其解,并且不相信opacity能決定哪個元素堆在前面,歡迎來社區(qū)提問,當(dāng)?shù)谝淮卧谶@個問題上被困擾時我同樣很震驚。
希望接下來的內(nèi)容能夠讓你對這個問題更清楚些。
堆棧順序
Z-index看上去如此簡單:高的z-index堆在低的z-index的前面,對嗎?這實(shí)際上是錯的,是z-index問題的一部分。它看上去如此的簡單,以至于很多開發(fā)者沒有花相應(yīng)的時間去讀相關(guān)的規(guī)則。
每一個在HTML文檔中的元素既可以在其他元素的前面,也可以在其他元素的后面。這就是所謂的堆棧順序。決定這個順序的規(guī)則被十分清楚的定義在說明文檔中,但是就像之前我已經(jīng)提到過,這些文檔沒有被大多數(shù)開發(fā)者們完全弄明白。
當(dāng)z-index和position屬性不被包括在內(nèi)時,這些規(guī)則相當(dāng)簡單:基本上,堆棧順序和元素在HTML中出現(xiàn)的順序一樣。(好吧,其實(shí)是有一點(diǎn)復(fù)雜的,但是只要你不使用壓縮邊界來重疊行內(nèi)元素,你可能不會遇到邊界問題。)
當(dāng)你把位置屬性也包括在內(nèi)介紹時,任何定位元素(和他們的子元素)都在非定位元素前被顯示出來。(說一個元素被“定位”意思是它有一個不同于靜態(tài)的位置值,例如相對的,絕對的,等等。)
最 后,當(dāng)z-index被提及時,事情變的有點(diǎn)兒復(fù)雜。最初,很自然的假設(shè)帶有高z-index值的元素會在帶有低z-index值的元素前面,但是后來發(fā) 現(xiàn)沒那么簡單。首先,z-index只對定位元素起作用。如果你嘗試對非定位元素設(shè)定一個z-index值,那么肯定不起作用。其次,z-index值能 創(chuàng)建堆棧上下文環(huán)境,并且突然發(fā)現(xiàn)看似簡單的東西變的更加復(fù)雜了。
堆棧上下文
一組具有共同雙親的元素,按照堆棧順序一起向前或向后移動構(gòu)成了所謂的堆棧上下文。充分理解堆棧上下文是真正掌握z-index和堆棧順序工作原理的關(guān)鍵。
每 一個堆棧上下文都有一個HTML元素作為它的根元素。當(dāng)一個新的堆棧上下文在一個元素上形成,那么這個堆棧上下文會限制所有的子元素以堆棧的順序存儲在一 個特別的地方。那意味著一旦一個元素被包含在處于底部堆棧順序的堆棧上下文中,那么就沒有辦法先出現(xiàn)于其他處于更高的堆棧順序的不同堆棧上下文元素,就算 z-index值是十億也不行!
現(xiàn)在,堆棧上下文有三種方法可以在一個元素上形成:
- 當(dāng)一個元素是文檔的根元素時(<html>元素)
- 當(dāng)一個元素有一個position值而不是static,有一個z-index值而不是auto
- 當(dāng)一個元素有一個opacity值小于1
前兩種形成堆棧上下文的方法具有很大意義并且被廣大Web開發(fā)者所理解(即使他們不知道這些被叫做什么)。第三種方法(opacity)幾乎從來沒在w3c說明文檔之外被提及過。
用堆棧順序決定一個元素的位置
實(shí)際上,為一個頁面上的所有元素決定全局堆棧順序(包括邊界、背景、文本節(jié)點(diǎn)、等等)是極度復(fù)雜的,并且遠(yuǎn)遠(yuǎn)超越了本文講述的范圍(再一次,參考文檔)。但是我們最大的目的,就是基本了解這個順序,它能夠在很長一段時間內(nèi)幫助我們提高CSS開發(fā)的可預(yù)測性。所以,讓我們打破順序,分解為獨(dú)立的堆棧上下文。
在同樣的堆棧上下文里的堆棧順序
下面是幾條基本的規(guī)則,來決定在一個單獨(dú)的堆棧上下文里的堆棧順序(從后向前):
- 堆棧上下文的根元素
- 定位元素(和他們的子元素)帶著負(fù)數(shù)的z-index值(高的值被堆疊在低值的前面;相同值的元素按照在HTML中出現(xiàn)的順序堆疊)
- 非定位元素(按照在HTML中出現(xiàn)的順序排序)
- 定位元素(和他們的子元素)帶著auto的z-index值(按照在HTML中出現(xiàn)的順序排序)
- 定位元素(和他們的子元素)帶著正z-index值(高的值被堆疊在低值的前面;相同值的元素按照在HTML中出現(xiàn)的順序堆疊)
注 解:定位元素帶有負(fù)的z-index值被在一個堆棧上下文中先排序,這意味著他們出現(xiàn)在所有其他元素的后面。正因如此,它使一個元素出現(xiàn)在自己父元素之后 成為可能,這以前通常是不可能的事。當(dāng)然,這局限于它的父元素與它在同一個堆棧上下文,并且不是那個堆棧上下文的根元素。一個偉大的例子如Nicolas Gallagher的CSS不用圖像降低陰影。
全局堆棧順序
堅定的理解了為什么/什么時候新的堆棧上下文形成,同時掌握了同一個堆棧上下文的堆棧順序,現(xiàn)在讓你來找出一個特定元素將出現(xiàn)在全局堆棧里的順序不是那么糟糕了吧?
避免錯誤的關(guān)鍵是能夠發(fā)現(xiàn)新的堆棧上下文什么時候形成。如果你對一個元素設(shè)置了z-index值為十億但是它沒有在堆棧順序中向前移動,檢查一下它的祖先樹,看是否它的父節(jié)點(diǎn)形成了堆棧上下文。如果是那樣的話,你的z-index值即使有十億也不會給你帶來好處。
包扎救治
回到之前的原始問題,我已經(jīng)重建了這個HTML的結(jié)構(gòu),添加了一些注釋,每一個標(biāo)簽指明了它在堆棧里的順序。這個順序是假設(shè)最初的CSS。
1 2 3 4 5 6 7 8 9 |
<div><!-- 1 --> <span><!-- 6 --></span> </div> <div><!-- 2 --> <span><!-- 4 --><span> </div> <div><!-- 3 --> <span><!-- 5 --></span> </div> |
當(dāng)我們添加opacity到第一個<div>,堆棧順序像下面這樣改變:
1 2 3 4 5 6 7 8 9 |
<div><!-- 1 --> <span><!-- 1.1 --></span> </div> <div><!-- 2 --> <span><!-- 4 --><span> </div> <div><!-- 3 --> <span><!-- 5 --></span> </div> |
span.red曾經(jīng)的順序是6,但現(xiàn)在改為1.1。我已經(jīng)使用“.”來標(biāo)注一個新的上下文環(huán)境的形成。span.red現(xiàn)在是那個新的上下文的第一個元素。
現(xiàn) 在似乎更清晰了,關(guān)于為什么紅色盒子跑到其他盒子的后面。原始的例子只包含兩個堆棧上下文,根元素和形成span.red的那個。當(dāng)我們添加 opacity到span.red的父節(jié)點(diǎn)上,形成了第三個堆棧上下文,結(jié)果顯示在span.red上的z-index值只能應(yīng)用在那個新的堆棧上下文 中。因?yàn)榈谝粋€<div>(應(yīng)用opacity的那個)和它的兄弟元素沒有position或者z-index值的集合,他們的堆棧順序是由 他們在HTML里的源順序決定的,也就是說第一個<div>,和它的堆棧上下文里的所有元素被第二個和第三個<div>元素分 離。
本文地址:http://m.likemindfilms.com/tutorial/wd1410.html