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