原作者:doyoe
原文鏈接:http://blog.doyoe.com/2014/01/21/css/%E4%BD%A0%E9%9C%80%E8%A6%81%E4%BA%86%E8%A7%A3%E7%9A%84z-index%E4%B8%96%E7%95%8C/
在我看來(lái),z-index
給了我們?nèi)粘9ぷ髦幸詷O大的幫助,我們用它來(lái)定義元素的層疊級(jí)別(stack level)。受益于它,你能做Popup, DropDown, Tips, 圖文替換等等。
在開(kāi)始本篇之前,或許我們要先了解一下關(guān)于z-index的基本信息。
每個(gè)元素都具有三維空間位置,除了水平和垂直位置外,還能在 “Z軸” 上層層相疊、排列。元素在 “Z軸” 方向上的呈現(xiàn)順序,由層疊上下文和層疊級(jí)別決定。
在文檔中,每個(gè)元素僅屬于一個(gè)層疊上下文。元素的層疊級(jí)別為整型,它描述了在相同層疊上下文中元素在 “Z軸” 上的呈現(xiàn)順序。
同一層疊上下文中,層疊級(jí)別大的顯示在上,層疊級(jí)別小的顯示在下,相同層疊級(jí)別時(shí),遵循后來(lái)居上的原則,即其在HTML文檔中的順序。
不同層疊上下文中,元素呈現(xiàn)順序以父級(jí)層疊上下文的層疊級(jí)別來(lái)決定呈現(xiàn)的先后順序,與自身的層疊級(jí)別無(wú)關(guān)。
z-index: auto | <integer>
z-index
接受的屬性值為:關(guān)鍵字auto和整數(shù),整數(shù)可以是負(fù)值(Firefox2.0及之前不支持負(fù)值)。
需要注意的是 z-index
雖然很給力,卻只能應(yīng)用于定位元素(即設(shè)置了 position
屬性為非 static
值),其它情況下,z-index
將被忽略。
對(duì)于定位元素而言,z-index
意味著:
在規(guī)范中說(shuō)明:當(dāng)某個(gè)元素的 z-index
未顯式定義或者被指定為 auto
時(shí),該元素不會(huì)產(chǎn)生新的局部層疊上下文。也就是說(shuō)它可以和兄弟,祖先,后輩元素處在同一個(gè)堆疊上下文中,它們被放在一起比較層疊級(jí)別,兒子可以蓋住祖先,父親也可以蓋住兒子,兒子甚至可以越過(guò)祖先,蓋住祖先的兄弟,在層疊上下文中,它們是并級(jí)的關(guān)系。來(lái)看這樣一個(gè)例子 DEMO1
: z-index與創(chuàng)建層疊上下文
值得高興的是,大部分瀏覽器都實(shí)現(xiàn)了這個(gè)特性;不過(guò)在IE6/7下,不論 z-index
值是否被顯式定義,都將產(chǎn)生新的局部層疊上下文,也就是說(shuō)子元素不可以越過(guò)是定位元素的父親,子元素都處在新創(chuàng)建的局部層疊上下文中,只能在內(nèi)部進(jìn)行層疊級(jí)別的比較。
某區(qū)域內(nèi)有個(gè)浮層提示或者下拉菜單,于是可能需要遮住該區(qū)域之下的區(qū)域。
<div class="a">
...
<div class="tips">我是一個(gè)簡(jiǎn)陋的浮層提示</div>
</div>
<div class="b">
...
</div>
.a{position:relative;}
.tips{position:absolute;z-index:99;}
如上HTML/CSS代碼,很顯然,浮層 tips
將可以覆蓋在其父級(jí)元素 a
的兄弟元素 b
之上。
于是你的意圖得到實(shí)現(xiàn),效果如下 圖一
:
(圖一)
這是具體的實(shí)現(xiàn)例子 DEMO2
: z-index實(shí)現(xiàn)元素層疊。
不過(guò)很顯然,從 DEMO2
來(lái)看,你依然無(wú)法準(zhǔn)確的判斷出在各瀏覽器下,tips
能蓋住 b
是因?yàn)槠涓讣?jí)的定位還是本身的定位。
但是我們可以做這樣一個(gè)測(cè)試,我們讓 b
也擁有定位,Code如下:
.a{position:relative;}
.tips{position:absolute;z-index:99;}
.b{position:relative;}
這段代碼run完之后,就比較糾結(jié)了,你能得到的效果將會(huì)如下 圖二
:
(圖二)
當(dāng)然要給出具體實(shí)現(xiàn) DEMO3
: 驗(yàn)證創(chuàng)建局部層疊上下文。
首先,我們來(lái)解讀一下這個(gè)例子:因?yàn)?a
和 b
都是 relative
且沒(méi)有定義 z-index
(等同于z-index:auto),根據(jù)后來(lái)居上的原則,此時(shí) b
的層疊級(jí)別是要高于 a
的,意思就是說(shuō) a
是無(wú)法遮住 b
的。不過(guò)從 DEMO3
中,我們看到 a
的子元素 tips
遮住了 b,這就表示 tips
能越過(guò)它,所以可以判斷出 a
沒(méi)有創(chuàng)建新的局部層疊上下文。很明顯,這是完全吻合標(biāo)準(zhǔn)對(duì)此的定義。
不過(guò)這是在非IE6/7之下結(jié)果。在IE6/7下,我們看到 tips
并沒(méi)能遮住 b
,也就是說(shuō) tips
無(wú)法越過(guò)父級(jí),因?yàn)?a
創(chuàng)建了新的局部層疊上下文,而 a
的層疊級(jí)別又比 b 低,所以 tips
無(wú)法遮住 b
,這也就是在IE6/7下常出現(xiàn)覆蓋Bug的根源。
結(jié)合 DEMO2
和 DEMO3
,你能很肯定的得出以下結(jié)論:
在實(shí)際工作中,有些情況可能是你沒(méi)注意或者已然存在的。比如你事先可能并不知道 b
也是定位元素,或者由于某些原因,你需要將其設(shè)置為定位元素,于是可能出現(xiàn)各種兼容問(wèn)題。如果你不了解 z-index
是如何創(chuàng)建局部層疊上下文,且又沒(méi)注意到IE6/7的實(shí)現(xiàn)錯(cuò)誤,那么處理起這樣的問(wèn)題將會(huì)讓你深陷泥潭。
所以在實(shí)際的場(chǎng)景中,如果是為了相互覆蓋而設(shè)置為定位,那么顯式的定義 z-index
值,將可避免出現(xiàn)創(chuàng)建新局部層疊上下文差異。
如果需要越過(guò)祖先和其它區(qū)塊內(nèi)部元素進(jìn)行相互層疊,那么考慮IE6/7的情況,也應(yīng)該盡量避免給父級(jí)元素進(jìn)定位。
我們知道 opacity
屬性是用來(lái)設(shè)置元素不透明度的。但可能知道 opacity
和層疊上下文有關(guān)的不多,不過(guò)沒(méi)關(guān)系,這里我們簡(jiǎn)單聊聊這個(gè)話題,有兩點(diǎn)必須注意:
簡(jiǎn)單來(lái)說(shuō),當(dāng)一個(gè)普通的元素定義了 opacity
的值小于1時(shí)(比如 opacity:.5),那么該元素的層疊級(jí)別將會(huì)高于普通元素,其效果類同于定位元素沒(méi)有顯式定義 z-index
的情況,唯一的區(qū)別是沒(méi)有顯式定義 z-index
的定位元素不會(huì)產(chǎn)生局部層疊上下文,而定義了 opacity
值小于1的元素會(huì)產(chǎn)生新的局部層疊上下文。
假定我們有 a
, b
, c
三個(gè)元素,它們相互層層覆蓋在一起,如果這時(shí)將 a
元素定義為 opacity:.8
,你知道結(jié)果會(huì)怎樣嗎?
<div class="a">a</div>
<div class="b">b</div>
<div class="c">c</div>
.a,.b,.c{width:100px;height:100px;}
.a{opacity:.8;background:#999;}
.b{margin:-70px 0 0 30px;background:#090;}
.c{margin:-70px 0 0 60px;background:#f00;}
如果你看明白了我對(duì)于 opacity
與層疊上下文的描述,相信你可以猜到結(jié)果,是的,a
元素將會(huì)覆蓋 b
和 c
元素,雖然它在HTML文檔中出現(xiàn)在 b
和 c
之前,且不是定位元素。
必須看看具體的示例不是么?DEMO4
: opacity與局部層疊上下文猜想。
如果我們將 b
和 c
設(shè)置為定位元素,又將會(huì)如何呢?
.a,.b,.c{width:100px;height:100px;}
.a{opacity:.8;background:#999;}
.b{position:relative;margin:-70px 0 0 30px;background:#090;}
.c{position:relative;margin:-70px 0 0 60px;background:#f00;}
不急,我們可以接著看示例 DEMO5
: opacity與局部層疊上下文猜想2。
從 DEMO4
和 DEMO5
兩例,我們可以驗(yàn)證:當(dāng)一個(gè)普通元素定義了 opacity
為小于1的值時(shí),該元素將像定位元素一樣擁有層疊級(jí)別,可以覆蓋普通元素,并且其層疊級(jí)別與未顯式定義 z-index
的定位元素一樣。
與未顯式定義 z-index
的定位元素唯一不同的是 opacity
值小于1的元素會(huì)創(chuàng)建局部層疊上下文。
創(chuàng)建局部層疊上下文意味著什么,前文我們已經(jīng)詳述過(guò)。所以不再贅述,這里只給一個(gè)示例用以驗(yàn)證該特性。先奉上代碼:
<div class="a">a
<div class="d">d</div>
</div>
<div class="b">b</div>
<div class="c">c</div>
.a,.b,.c,.d{width:100px;height:100px;}
.a{opacity:.8;background:#999;}
.b{position:relative;margin:-70px 0 0 30px;background:#090;}
.c{position:relative;margin:-70px 0 0 60px;background:#f00;}
.d{position:absolute;z-index:99;height:50px;background:#090;}
你可以先看看具體結(jié)果 DEMO6
: opacity創(chuàng)建新局部層疊上下文。
你會(huì)發(fā)現(xiàn)雖然 a
的子元素 d
將 z-index
定義為99,但 d
仍然無(wú)法遮住 b
和 c
元素,這是因?yàn)?a
創(chuàng)建了新的局部層疊上下文,d
元素?zé)o法超越父級(jí)。
需要注意的是,此時(shí)就算 a
元素變成了定位元素,也不能改變其會(huì)創(chuàng)建新局部層疊上下文的命運(yùn),因?yàn)樗O(shè)置了 opacity:.8
。
按照我們前文所說(shuō),如果 a
沒(méi)有定義 opacity:.8
,但卻像 b
和 c
元素一樣設(shè)置了 relative
,那么其子元素 d
將可以覆蓋 b
和 c
,至于這個(gè)例子就不再奉上了,大家隨便寫個(gè)測(cè)試一下即可。
上述都是理論性的東西,相對(duì)枯燥,來(lái)個(gè)實(shí)際點(diǎn)的應(yīng)用場(chǎng)景。
我們聊聊圖文替換的事,相對(duì)于使用較廣的方案如:縮進(jìn)正/負(fù)值(正/負(fù)text-indent)、超小字體、margin溢出、padding溢出、line-height溢出、透明字體、display:none、visibility:hidden等方案而言,使用 z-index
負(fù)值的方案,有一些明顯的優(yōu)勢(shì):
先來(lái)看看一個(gè)圖文替換的例子 DEMO7
: 圖文替換實(shí)例。
在不同的網(wǎng)絡(luò)環(huán)境下,它的表現(xiàn)如下 圖三
:
(圖三)
具體的Code很簡(jiǎn)單:
<a href="#top" title="回到頂部"><span>TOP▲</span></a>
a,a span{display:inline-block;width:38px;height:38px;}
a{background:url(images/ico.png) no-repeat;}
a:hover{background-position:0 -39px;color:#fff;}
a span{position:relative;z-index:-1;background-color:#eee;}
a:hover span{background-color:#999;}
你會(huì)發(fā)現(xiàn)我們將 span
設(shè)置為了 z-index:-1
,此時(shí)它的層疊級(jí)別將比正常的元素還要低,所以它可以被其父元素超鏈接a蓋住,從而在圖片正常載入時(shí)顯示父元素的背景圖,在網(wǎng)絡(luò)環(huán)境不好圖片載入有問(wèn)題時(shí),顯示自身。
很多時(shí)候,要實(shí)現(xiàn)一個(gè)需求可能有無(wú)數(shù)種解決方案,能夠適應(yīng)情況越多的方案毫無(wú)疑問(wèn)會(huì)脫穎而出,這就要求我們可以去更多的思考,而不是更多的拷貝。
更多建議: