新聞資訊

關于(yú)z-index的(de)真正問題

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