【CSS】814- 關(guān)于 z-index,你可能一直存在誤區(qū)

原文地址:What You May Not Know About the Z-Index Property 原文作者:Steven Bradley 譯者:Chor
z-index 這個(gè)屬性表面看上去很簡(jiǎn)單,但如果你想搞清楚其工作原理的話,其實(shí)是有不少值得探討之處的。本文將從層疊上下文(stacking contexts)和一些實(shí)際案例出發(fā),談一談 z-index 的內(nèi)部工作原理。
CSS 為盒模型的布局提供了三種不同的定位方案[1] :
正常文檔流 浮動(dòng) 定位
最后一種方案(特指絕對(duì)定位)將會(huì)把元素從正常文檔流中完全移走,其最終的落腳點(diǎn)將取決于開(kāi)發(fā)者。
通過(guò)設(shè)置 top,left,bottom 和 right 的值,你可以在二維空間中對(duì)元素進(jìn)行定位,但 CSS 同時(shí)也允許你使用 z-index 屬性[2] 把它放置在三維空間中。
表面看起來(lái),z-index 似乎是一個(gè)很簡(jiǎn)單的屬性,你給它設(shè)置哪個(gè)值,元素就會(huì)位于 y 軸的哪個(gè)位置,就這樣。但它實(shí)際上并沒(méi)有我們想象的這么簡(jiǎn)單,這個(gè)屬性背后是一系列決定元素所在層級(jí)的規(guī)則。
為了保證我們?cè)谕粋€(gè)“頻道”上,這里我先普及一些基礎(chǔ)概念,之后再解釋層疊的相關(guān)知識(shí),并在一些場(chǎng)景中體會(huì) ?z-index[3] 作用的機(jī)制。
Z-Index 的基礎(chǔ)概念
對(duì)于三維空間坐標(biāo)系,你肯定很熟悉了。x 軸代表水平方向,y 軸代表垂直方向,z 軸則代表我們的目光向頁(yè)面(屏幕)看進(jìn)去的時(shí)候,各元素的布局情況。

由于屏幕是一塊二維平面,我們實(shí)際上并沒(méi)有真的看到 z 軸,更多的是通過(guò)透視的形式。具體地說(shuō),多個(gè)元素共享同一塊二維平面時(shí),有的元素在頂部,有的元素在底部,我們由此感受到了 z 軸的存在。
為了決定某個(gè)元素在 z 軸方向上的位置,CSS 允許我們?yōu)?z-index 屬性設(shè)置三種值[4]:
auto(默認(rèn)值) 整數(shù) inherit
我們主要看一下整數(shù)值。它可以是正整數(shù)、負(fù)整數(shù)或者 0,值越大,元素就離我們“越近”,值越小,元素自然也就離我們“越遠(yuǎn)”。
如果兩個(gè)元素在定位之后共享同一塊二維空間,那么在這塊空間中, z-index 越大的元素將可能覆蓋 z-index 較小的元素。
很顯然,上面講的這些都是非常容易理解的,并且也和我們的直覺(jué)相符合。不過(guò),下面的問(wèn)題恐怕就不是很好回答了:
當(dāng)設(shè)置了定位和 z-index的元素與一個(gè)位于正常文檔流中的元素重疊時(shí),哪一個(gè)在頂層呢?一個(gè)元素設(shè)置定位,另一個(gè)元素設(shè)置浮動(dòng),哪一個(gè)在頂層呢? 如果父元素和子元素都設(shè)置了定位,會(huì)發(fā)生什么事?
為了更好地理清這些問(wèn)題,我們有必要進(jìn)一步理解與 z-index 工作原理相關(guān)的一些概念,也就是層疊上下文、層疊等級(jí)和層疊順序。
層疊上下文和層疊等級(jí)
針對(duì)層疊上下文和層疊等級(jí)[5] ,可能很難給出一個(gè)清晰易懂的概念,所以我們這里用通俗的例子來(lái)理解。想象一下,現(xiàn)在有一張桌子,上面擺滿了各種東西。那么這張桌子就代表了一個(gè)層疊上下文,假設(shè)還有另一張與之并排的桌子,那么就產(chǎn)生了另一個(gè)層疊上下文。

如圖所示,層疊上下文 1 指的就是文檔根部,而層疊上下文 2 和 3 位于 1 的某個(gè)層疊等級(jí)中。此外,這兩個(gè)層疊上下文各自會(huì)包含新的層疊等級(jí)。
現(xiàn)在想象一下,第一張桌子上面并排擺了四個(gè)磚頭,這四個(gè)磚頭上面放著一個(gè)玻璃杯,而玻璃杯上面還放著一個(gè)水果盤(pán)。那么,磚頭、玻璃杯、水果盤(pán),各自都處于不同的層疊等級(jí)中,但它們共處于“桌子”這一層疊上下文中。
對(duì)每一個(gè)網(wǎng)頁(yè)來(lái)說(shuō),默認(rèn)都會(huì)創(chuàng)建一個(gè)層疊上下文[6] ,這個(gè)上下文(這張桌子)的根部就是 html 元素,html 元素的所有子元素都會(huì)位于這個(gè)默認(rèn)的層疊上下文中的某個(gè)層疊等級(jí),就好比東西會(huì)擺放在桌子的不同位置上一樣。
當(dāng)你給某個(gè)元素設(shè)置一個(gè)非 auto 的 z-index 時(shí),就會(huì)創(chuàng)建一個(gè)新的 層疊上下文[7] ,它和它所包含的層疊等級(jí)都是獨(dú)立于其它層疊上下文和層疊等級(jí)的,就好比你搬了一張新的桌子放在房間里,它和舊的桌子是互相獨(dú)立的。
層疊順序
我們可以通過(guò)一個(gè)非常簡(jiǎn)單的例子來(lái)理解層疊順序,這個(gè)例子甚至還不需要涉及到 定位元素[8] 。
想象一下,現(xiàn)在有一個(gè)非常簡(jiǎn)單的網(wǎng)頁(yè),不考慮默認(rèn)的 當(dāng)加載頁(yè)面的時(shí)候,你覺(jué)得會(huì)看到什么? 這個(gè)自然不用多想,引入眼簾的肯定是一大片的藍(lán)色,同時(shí)還有一個(gè)此前設(shè)置好尺寸的紅色塊級(jí)元素。除非你做了額外的設(shè)置,否則這個(gè)元素將正常地出現(xiàn)在左上角。 你可能會(huì)說(shuō)“就這?太簡(jiǎn)單了吧”,不過(guò)有一個(gè)問(wèn)題可能不那么簡(jiǎn)單:為什么紅色的塊級(jí)元素就一定會(huì)位于藍(lán)色背景的上層呢?為什么我們看到的就是 在這個(gè)簡(jiǎn)單的例子中,根據(jù)規(guī)則,正常文檔流的子塊( 雖然上面這個(gè)例子只涉及到了兩個(gè)層疊等級(jí),但實(shí)際上,在一個(gè)層疊上下文中,一共可能出現(xiàn)七個(gè)層疊等級(jí),從最低到最高排列,依次是: 這七個(gè)層疊等級(jí)就構(gòu)成了層疊順序的規(guī)則。符合層疊等級(jí)七的元素,會(huì)比層疊等級(jí)在一到六的元素更“貼近我們”,符合層疊等級(jí)五的元素,會(huì)比層疊等級(jí)二的元素更“貼近我們”,以此類推。 第一次學(xué)習(xí)這些層疊規(guī)則的時(shí)候,我感覺(jué)收獲了很多新的東西。如果只著眼于層疊等級(jí)二、六和七(也就是涉及到 我之前就是這樣,在看到這些規(guī)則之前,以為除了正的和負(fù)的 還有一個(gè)有趣的細(xì)節(jié)是,非定位的元素實(shí)際位于四種不同的層疊等級(jí)中。乍一想覺(jué)得很奇怪,不過(guò)其實(shí)這是很合理的。假設(shè)所有的非定位元素都位于同一個(gè)層疊等級(jí),那么我們就沒(méi)辦法在 我前面提到過(guò)很多次,當(dāng)你給一個(gè)元素設(shè)置非 auto 的 重新回顧一下之前拿桌子做比喻的案例。一開(kāi)始的時(shí)候,我們的桌子上擺滿了四塊磚頭,上面是一個(gè)玻璃杯,再上面是一個(gè)水果盤(pán)。現(xiàn)在,假設(shè)又有一張新的桌子,它擺放的東西和舊桌子差不多,唯一的不同是,新桌子少了一個(gè)水果盤(pán)。 不難想象,舊桌子的水果盤(pán)是整個(gè)房間中位于最頂層的物品(它有最大的 對(duì)于網(wǎng)頁(yè)上的定位元素來(lái)說(shuō),其實(shí)道理是一樣的。假設(shè)有如下代碼,思考一個(gè)問(wèn)題: HTML: CSS: 盡管 由于 看到這個(gè)例子是不是有一種熟悉的味道?我也曾經(jīng)被 在最初學(xué)習(xí) 最后,記住一個(gè)很重要的結(jié)論:定位元素可以創(chuàng)建新的層疊上下文,在這個(gè)上下文中的所有層疊等級(jí),都會(huì)高于或者低于另一個(gè)層疊上下文的所有層疊等級(jí)。 定位方案: https://www.w3.org/TR/CSS2/visuren.html#positioning-scheme z-index 屬性: http://www.w3.org/TR/CSS2/visuren.html#layers z-index: http://www.vanseodesign.com/css/css-stack-z-index/ z-index 屬性設(shè)置三種值: http://www.w3.org/TR/CSS21/visuren.html#propdef-z-index 層疊上下文和層疊等級(jí): http://timkadlec.com/2008/01/detailed-look-at-stacking-in-css/ 層疊上下文: https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context 層疊上下文: http://www.w3.org/TR/CSS21/zindex.html 定位元素: http://www.vanseodesign.com/css/css-positioning/ 深入理解 z-index: http://coding.smashingmagazine.com/2009/09/15/the-z-index-css-property-a-comprehensive-look/ 回復(fù)“加群”與大佬們一起交流學(xué)習(xí)~, , 等元素,就只需要考慮每個(gè)網(wǎng)頁(yè)至少都會(huì)有的一個(gè) html 的背景顏色為藍(lán)色,設(shè)置 div 的背景顏色為紅色,并設(shè)置寬高。div 位于 html 的上層呢?原因是,它們都遵循了層疊順序的規(guī)則。div)的層級(jí)將會(huì)高于根元素(html)的背景和邊框。我們看到div 位于頂層,這是因?yàn)樗膶盈B等級(jí)更高。z-index 為負(fù)數(shù)的子元素以及由它所產(chǎn)生的層疊上下文z-index 為 0 的、定位的子元素以及由它所產(chǎn)生的層疊上下文z-index 為正數(shù)的、定位的子元素以及由它所產(chǎn)生的層疊上下文,它是整個(gè)上下文中層疊等級(jí)最高的
z-index 的等級(jí)),那么大部分時(shí)候,我們對(duì)于 z-index 的理解是正確的。正的 z-index 的層級(jí)比 0 要高,而 0 又比負(fù)的要高,一切都符合直覺(jué),可能大多數(shù)人到這里就不繼續(xù)往后探究了。z-index ,其它情況都可以看作是 z-index 為0 —— 不過(guò)現(xiàn)在我們很清楚了,這種想法是錯(cuò)誤的。事實(shí)是,大部分元素的層級(jí)都要低于 z-index:0。div (塊級(jí)盒)上看到文本(內(nèi)聯(lián)盒)了。來(lái)看個(gè)案例
z-inde 時(shí),會(huì)創(chuàng)建一個(gè)新的、完全獨(dú)立的層疊上下文。z-index),不過(guò),如果把舊桌子以及它上面的所有東西整體搬到地下室呢?此時(shí),水果盤(pán)的層級(jí)會(huì)比新桌子上的每一個(gè)物品都要低,這是因?yàn)?,放置水果盤(pán)的舊桌子整體已經(jīng)低于新桌子了。div.two 和 div.four,哪個(gè)在上哪個(gè)在下?<div?class="one">
??<div?class="two">div>
??<div?class="three">div>
div>
<div?class="four">div>div?{
??width:?200px;
??height:?200px;
??padding:?20px;
}
?
.one,?.two,?.three,?.four?{
??position:?absolute;
}
??
.one?{
??background:?#f00;
??outline:?5px?solid?#000;
??top:?100px;
??left:?200px;
??z-index:?10;
}
??
.two?{
??background:?#0f0;
??outline:?5px?solid?#000;
??top:?50px;
??left:?75px;
??z-index:?100;
}
?
.three?{
??background:?#0ff;
??outline:?5px?solid?#000;
??top:?125px;
??left:?25px;
??z-index:?150;
}
?
.four?{
??background:?#00f;
??outline:?5px?solid?#ff0;
??top:?200px;
??left:?350px;
??z-index:?50;
}div.two 有更高的 z-index(100),但在頁(yè)面上,它的層級(jí)實(shí)際上比 div.four (z-index 為50)要低。下圖就是頁(yè)面元素的層級(jí)情況,根據(jù)黑色和黃色邊框,我們可以區(qū)分每個(gè)元素生成的不同的層疊上下文。
div.two ?位于 div.one 中,所以它的 z-index 是和 div.one 的層疊上下文相關(guān)的,也就是說(shuō),實(shí)際表現(xiàn)出來(lái)的 z-index 是下面這樣的:div.one 和內(nèi)部包含的一切將會(huì)在層級(jí)上低于 div.four,無(wú)論給 ?div.one 的子元素設(shè)置多大的 z-index,子元素的層級(jí)都無(wú)法超過(guò) div.four。z-index 這么坑過(guò)一兩次。我們都曾疑惑一個(gè)問(wèn)題,為什么一個(gè) z-index 非常大的元素,在層級(jí)上始終無(wú)法超過(guò)一個(gè) z-index 比它小很多的元素?相信在學(xué)習(xí)了這些案例之后,你已經(jīng)豁然開(kāi)朗了。總結(jié)
z-index 的時(shí)候,我們都會(huì)認(rèn)為它很簡(jiǎn)單,這不就是代表元素在 z 軸上的位置嗎?不過(guò)我們現(xiàn)在知道了,事情遠(yuǎn)沒(méi)有這么簡(jiǎn)單。深入理解 z-index[9] 一文也揭示了 z-index 背后一些原理層面的東西,包括層疊上下文,層疊等級(jí)以及一系列決定元素的層疊順序的規(guī)則。拓展閱讀
參考資料

