新聞資(zī)訊

關于z-index的真正問題

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