詳解CSS中的z-index屬性在層疊布局中的用法
z-index的重要性
在我看來(lái),z-index 給了我們?nèi)粘9ぷ髦幸詷O大的幫助,我們用它來(lái)定義元素的層疊級(jí)別(stack level)。受益于它,你能做Popup, DropDown, Tips, 圖文替換等等。
在開(kāi)始本篇之前,或許我們要先了解一下關(guān)于z-index的基本信息。
W3C這樣描述
每個(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)。
順序規(guī)則
如果不對(duì)節(jié)點(diǎn)設(shè)定 position 屬性, 位于文檔流后面的節(jié)點(diǎn)會(huì)遮蓋前面的節(jié)點(diǎn).
- <div id="a">A</div>
- <div id="b">B</div>

定位規(guī)則
如果將 position 設(shè)為 static, 位于文檔流后面的節(jié)點(diǎn)依然會(huì)遮蓋前面的節(jié)點(diǎn)浮動(dòng), 所以 position:static 不會(huì)影響節(jié)點(diǎn)的遮蓋關(guān)系.
- <div id="a" style="position:static;">A</div>
- <div id="b">B</div>

如果將 position 設(shè)為 relative (相對(duì)定位), absolute (絕對(duì)定位) 或者 fixed (固定定位), 這樣的節(jié)點(diǎn)會(huì)覆蓋沒(méi)有設(shè)置 position 屬性或者屬性值為 static 的節(jié)點(diǎn), 說(shuō)明前者比后者的默認(rèn)層級(jí)高.
- <div id="a" style="position:relative;">A</div>
- <div id="b">B</div>

在沒(méi)有 z-index 屬性干擾的情況下, 根據(jù)這順序規(guī)則和定位規(guī)則, 我們可以做出更加復(fù)雜的結(jié)構(gòu). 這里我們對(duì) A 和 B 都不設(shè)定 position, 但對(duì) A 的子節(jié)點(diǎn) A-1 設(shè)定 position:relative. 根據(jù)順序規(guī)則, B 會(huì)覆蓋 A, 又根據(jù)定位規(guī)則 A' 會(huì)覆蓋 B.
- <div id="a">
- <div id="a-1" style="position:relative;">A-1</div>
- </div>
- <div id="b">B</div>

上面互相覆蓋在什么時(shí)候用到這樣的實(shí)現(xiàn)? 看起來(lái)偏門, 其實(shí)很常用, 比如說(shuō), 電子商務(wù)網(wǎng)站側(cè)欄的類目展示列表就可以用這個(gè)技巧來(lái)實(shí)現(xiàn).
下圖是某網(wǎng)站的類目展示區(qū)域, 二級(jí)類目的懸浮層覆蓋一級(jí)類目列表外框, 而一級(jí)類目的節(jié)點(diǎn)覆蓋二級(jí)類目的懸浮層. 如果使用 CSS 實(shí)現(xiàn)展示效果, 一級(jí)類目的外框相當(dāng)于上面例子中的 A, 一級(jí)類目的節(jié)點(diǎn)相當(dāng)于 A-1, 二級(jí)類目的懸浮層相當(dāng)于 B.
參與規(guī)則
我們嘗試不用 position 屬性, 但為節(jié)點(diǎn)加上 z-index 屬性. 發(fā)現(xiàn) z-index 對(duì)節(jié)點(diǎn)沒(méi)起作用.
- <div id="a" style="z-index:2;">A</div>
- <div id="b" style="z-index:1;">B</div>
- <div id="c" style="z-index:0;">C</div>

W3C 對(duì) z-index 屬性的描述中提到 在 z-index 屬性僅在節(jié)點(diǎn)的 position 屬性為 relative, absolute 或者 fixed 時(shí)生效.
The z-index property specifies the stack order of an element. Only works on positioned elements(position: absolute;, position: relative; or position: fixed;).
- <div id="a" style="z-index:2;">A</div>
- <div id="b" style="position:relative;z-index:1;">B</div>
- <div id="c" style="position:relative;z-index:0;">C</div>

默認(rèn)值規(guī)則
如果所有節(jié)點(diǎn)都定義了 position:relative. z-index 為 0 的節(jié)點(diǎn)與沒(méi)有定義 z-index 在同一層級(jí)內(nèi)沒(méi)有高低之分; 但 z-index 大于等于 1 的節(jié)點(diǎn)會(huì)遮蓋沒(méi)有定義 z-index 的節(jié)點(diǎn); z-index 的值為負(fù)數(shù)的節(jié)點(diǎn)將被沒(méi)有定義 z-index 的節(jié)點(diǎn)覆蓋.
- <div id="a" style="position:relative;z-index:1;">A</div>
- <div id="b" style="position:relative;z-index:0;">B</div>
- <div id="c" style="position:relative;">C</div>
- <div id="d" style="position:relative;z-index:0;">D</div>

通過(guò)檢查我們還發(fā)現(xiàn), 當(dāng) position 設(shè)為 relative, absolute 或者 fixed, 而沒(méi)有設(shè)置 z-index 時(shí), IE8 以上和 W3C 瀏覽器 (下文我們統(tǒng)稱為 W3C 瀏覽器) 的 z-index 默認(rèn)值是 auto, 但 IE6 和 IE7 是 0.
從父規(guī)則
如果 A, B 節(jié)點(diǎn)都定義了 position:relative, A 節(jié)點(diǎn)的 z-index 比 B 節(jié)點(diǎn)大, 那么 A 的子節(jié)點(diǎn)必定覆蓋在 B 的子節(jié)點(diǎn)前面.
- <div id="a" style="position:relative;z-index:1;">
- <div id="a-1">A-1</div>
- </div>
- <div id="b" style="position:relative;z-index:0;">
- <div id="b-1">B-1</div>
- </div>

如果所有節(jié)點(diǎn)都定義了 position:relative, A 節(jié)點(diǎn)的 z-index 和 B 節(jié)點(diǎn)一樣大, 但因?yàn)轫樞蛞?guī)則, B 節(jié)點(diǎn)覆蓋在 A 節(jié)點(diǎn)前面. 就算 A 的子節(jié)點(diǎn) z-index 值比 B 的子節(jié)點(diǎn)大, B 的子節(jié)點(diǎn)還是會(huì)覆蓋在 A 的子節(jié)點(diǎn)前面.
- <div id="a" style="position:relative;z-index:0;">
- <div id="a-1" style="position:relative;z-index:2;">A-1</div>
- </div>
- <div id="b" style="position:relative;z-index:0;">
- <div id="b-1" style="position:relative;z-index:1;">B-1</div>
- </div>

很多人將 z-index 設(shè)得很大, 9999 什么的都出來(lái)了, 如果不考慮父節(jié)點(diǎn)的影響, 設(shè)得再大也沒(méi)用, 那是無(wú)法逾越的層級(jí).
層級(jí)樹(shù)規(guī)則
可能你會(huì)覺(jué)得在 DOM 結(jié)構(gòu)中的兄弟節(jié)點(diǎn)會(huì)拎出來(lái)進(jìn)行比較并確定層級(jí), 其實(shí)不然.
- <div id="a" style="position:relative;z-index:2;">
- <div id="a-1" style="position:relative;z-index:0;">A-1</div>
- </div>
- <div id="b">
- <div id="b-1" style="position:relative;z-index:1;">B-1</div>
- </div>

我們認(rèn)為同時(shí)將 position 設(shè)為 relative, absolute 或者 fixed, 并且 z-index 經(jīng)過(guò)整數(shù)賦值的節(jié)點(diǎn), 會(huì)被放置到一個(gè)與 DOM 不一樣的層級(jí)樹(shù)里面, 并且在層級(jí)樹(shù)中通過(guò)對(duì)比 z-index 決定顯示的層級(jí). 上面的例子如果用層級(jí)樹(shù)來(lái)表示的話, 應(yīng)該如下圖所示.
圖中雖然 A-1 (z-index:0) 的值比 B-1 (z-index:1) 小, 但因?yàn)樵趯蛹?jí)樹(shù)里 A (z-index:2) 和 B-1 在一個(gè)層級(jí), 而 A 的值比 B-1 大, 根據(jù)從父規(guī)則, A-1 顯示在 B-1 前面.
參與規(guī)則 2
前面提到的參與規(guī)則認(rèn)為只要節(jié)點(diǎn)的 position 屬性為 relative, absolute 或者 fixed, 即可參與層級(jí)比較, 其實(shí)不準(zhǔn)確. 如果所有節(jié)點(diǎn)都定義了 position:relative, 并且將 z-index 設(shè)為整數(shù)值, 根據(jù)從父規(guī)則, 父節(jié)點(diǎn)的層級(jí)決定了子節(jié)點(diǎn)所在層級(jí).
- <div id="a" style="position:relative;z-index:0;">
- <div id="a-1" style="position:relative;z-index:100;">A-1</div>
- </div>
- <div id="b">
- <div id="b-1" style="position:relative;z-index:0;">
- <div id="b-1-1" style="position:relative;z-index:10;">B-1-1</div>
- </div>
- </div>
- <div id="c" style="position:relative;z-index:0;">
- <div id="c-1">
- <div id="c-1-1">
- <div id="c-1-1-1" style="position:relative;z-index:1;">C-1-1-1</div>
- </div>
- </div>
- </div>
例子中 A, B-1, C-1-1 作為父節(jié)點(diǎn), z-index 的值相同, 根據(jù)順序規(guī)則, C-1-1 在 B-1 之前, B-1 在 A 之前; 又根據(jù)從父規(guī)則, 無(wú)論子節(jié)點(diǎn)的 z-index 值是什么, C-1-1-1 在 B-1-1 之前, B-1-1 在 A-1 之前.
如果我們將所有父節(jié)點(diǎn)的 z-index 屬性去除, 詭異的事情發(fā)生了. IE6 和 IE7 瀏覽器顯示效果不變, 而 W3C 瀏覽器的子節(jié)點(diǎn)不再?gòu)母? 而是根據(jù)自身的 z-index 確定層級(jí).
- <div id="a" style="position:relative;">
- <div id="a-1" style="position:relative;z-index:100;">A-1</div>
- </div>
- <div id="b">
- <div id="b-1" style="position:relative;">
- <div id="b-1-1" style="position:relative;z-index:10;">B-1-1</div>
- </div>
- </div>
- <div id="c" style="position:relative;">
- <div id="c-1">
- <div id="c-1-1">
- <div id="c-1-1-1" style="position:relative;z-index:1;">C-1-1-1</div>
- </div>
- </div>
- </div>
根據(jù)默認(rèn)值規(guī)則, IE6 / IE7 和 W3C 瀏覽器上的元素存在 z-index 默認(rèn)值的區(qū)別. 我們相信, 僅當(dāng) position 設(shè)為 relative, absolute 或者 fixed, 并且 z-index 賦整數(shù)值時(shí), 節(jié)點(diǎn)被放置到層級(jí)樹(shù); 而 z-index 為默認(rèn)值時(shí), 只在 document 兄弟節(jié)點(diǎn)間比較層級(jí). 在 W3C 瀏覽器中, A, B-1 和 C-1-1 的 z-index 均為 auto, 不參與層級(jí)比較.
而在 IE6 和 IE7 中, 因?yàn)?z-index 的默認(rèn)值是 0, 所以也參與了層級(jí)比較.
設(shè)置了 position 而沒(méi)有 z-index 的節(jié)點(diǎn)雖然不參與層級(jí)樹(shù)的比較, 但還會(huì)在 DOM 中與兄弟節(jié)點(diǎn)進(jìn)行層級(jí)比較.
- <div id="a" style="position:relative;">
- <div id="a-1" style="position:relative;z-index:100;">A-1</div>
- </div>
- <div id="b">
- <div id="b-1">
- <div id="b-1-1" style="position:relative;z-index:10;">B-1-1</div>
- </div>
- </div>
- <div id="c" style="position:relative;">
- <div id="c-1">
- <div id="c-1-1">
- <div id="c-1-1-1" style="position:relative;z-index:1;">C-1-1-1</div>
- </div>
- </div>
- </div>
我們對(duì)上個(gè)例子改造一下, 將 B-1 的 position 屬性刪除后, W3C 瀏覽器顯示如下圖. 根據(jù)定位規(guī)則, A 和 C-1-1 會(huì)顯示在 B-1 的前面; 而根據(jù)順序規(guī)則, C-1-1 又顯示在 A 前面.
在 IE6 和 IE7 中, 因?yàn)?A 和 C-1-1 設(shè)置了 position:relative, 而且 z-index 的默認(rèn)值為 0, 所以也參與層級(jí)樹(shù)比較, 所以有如下效果.
總結(jié)
瀏覽器節(jié)點(diǎn)顯示層級(jí)是一個(gè)費(fèi)力的活, 今天你覺(jué)得 A 區(qū)塊會(huì)永遠(yuǎn)置頂, 但明天因?yàn)樾枨笞儎?dòng), 突然出現(xiàn) B 元素需要置頂. 一層一層往上堆砌, 某天回頭一看, 發(fā)現(xiàn)很多區(qū)塊交錯(cuò)在一起, 而且他們的值一個(gè)比一個(gè)大, 根本搞不清頭緒. 我覺(jué)得在操刀干活之前, 最好先將 position, z-index 和層級(jí)的關(guān)系搞搞清楚, 以免后患無(wú)窮.
另外, 非情非得已, 切勿用 JavaScript 計(jì)算 z-index, 并將某個(gè)節(jié)點(diǎn)的 z-index 設(shè)置成所有節(jié)點(diǎn)中層級(jí)最高.
因?yàn)槠L(zhǎng), 本文僅從節(jié)點(diǎn)屬性角度進(jìn)行討論, 沒(méi)有涉及 select 和 iframe 等特殊頁(yè)面節(jié)點(diǎn)考慮, 如果有機(jī)會(huì)下次再為大家分享.
相關(guān)文章
- 你對(duì)CSS層疊和繼承的概念和用法你是否熟悉,這里和大家分享一下,文檔中的一個(gè)元素可能同時(shí)被多個(gè)CSS選擇器選中,每個(gè)選擇器都有一些CSS規(guī)則,這就是層疊,而所謂繼承,就2011-01-27
- 我們知道文檔中的一個(gè)元素可能同時(shí)被多個(gè)css選擇器選中,每個(gè)選擇器都有一些css規(guī)則,這就是層疊。所謂繼承,就是父元素的規(guī)則也會(huì)適用于子元素。2010-03-14
- 下面小編就為大家?guī)?lái)一篇CSS默認(rèn)可繼承樣式詳解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-05-06
- 這篇文章主要介紹了CSS中的繼承,是CSS入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-07-16
CSS教程:學(xué)習(xí)CSS的繼承性-CSS教程-網(wǎng)頁(yè)制作-網(wǎng)頁(yè)教學(xué)網(wǎng)
所謂CSS的繼承是指被包在內(nèi)部的標(biāo)簽將擁有外部標(biāo)簽的樣式性質(zhì)。繼承特性最典型的應(yīng)用通常發(fā)揮在整個(gè)網(wǎng)頁(yè)的樣式預(yù)設(shè),需要指定為其它樣式的部份設(shè)定在個(gè)別元素里即可。這項(xiàng)2008-10-17CSS樣式表中繼承關(guān)系的空格與不空格-CSS教程-網(wǎng)頁(yè)制作-網(wǎng)頁(yè)教學(xué)網(wǎng)
這可能是一個(gè)非常簡(jiǎn)單的問(wèn)題,但是今天花一點(diǎn)點(diǎn)時(shí)間把這個(gè)簡(jiǎn)單的問(wèn)題在說(shuō)清晰一點(diǎn),相信大家對(duì)CSS的學(xué)習(xí)和認(rèn)識(shí)會(huì)很有幫助,強(qiáng)化一些概念的東西,對(duì)以后的工作效率的2008-10-17CSS教程:水平對(duì)齊(text-align)-CSS教程-網(wǎng)頁(yè)制作-網(wǎng)頁(yè)教學(xué)網(wǎng)
水平對(duì)齊(text-align),用以設(shè)定元素內(nèi)文本的水平對(duì)齊方式。 1.語(yǔ)法 text-align具體參數(shù)如下: 語(yǔ)法:text-align:left|right|center|justify 說(shuō)明:2008-10-17CSS教程:line-height屬性的繼承-CSS教程-網(wǎng)頁(yè)制作-網(wǎng)頁(yè)教學(xué)網(wǎng)
原文:http://www.planabc.net/2008/07/25/unitless-line-heights/ 淘寶商城的detail 頁(yè)面“產(chǎn)品詳情”部分是商家自定義區(qū)塊,曾出現(xiàn)這樣一個(gè)問(wèn)題: &2008-10-17CSS教程:行高line-height屬性(2)-CSS教程-網(wǎng)頁(yè)制作-網(wǎng)頁(yè)教學(xué)網(wǎng)
相關(guān)文章:CSS教程:行高line-height屬性(1) 7.3.3行高的計(jì)算與繼承 以em、ex和百分比為單位的行高,其基數(shù)是元素本身的字體尺寸。例如有代碼如下: <pstyle=&quo2008-10-17CSS教程:理解繼承屬性及應(yīng)用-CSS教程-網(wǎng)頁(yè)制作-網(wǎng)頁(yè)教學(xué)網(wǎng)
4.5繼承 在本書(shū)的[3.3.2繼承與層疊]一節(jié)曾經(jīng)簡(jiǎn)要介紹過(guò)繼承:(X)HTML元素可以從其父元素那里繼承部分CSS屬性,即使當(dāng)前元素并沒(méi)有定義該屬性。 4.5.1值的繼承 繼承也是2008-10-17

