天天看點

CSS 中重要的層疊概念

最近在項目的過程中遇到了一個問題,menu-bar希望始終顯示在最上面,而在之後的元素都顯示在它之下,當時設定了 z-index 也沒有效果,不知道什麼原因,是以找了一下css有關層疊方面的資料,解決了這個問題,這裡記錄一下~

螢幕是一個二維平面,然而HTML元素卻是排列在三維坐标系中,x為水準位置,y為垂直位置,z為螢幕由内向外方向的位置,我們在看螢幕的時候是沿着z軸方向從外向内的;由此,元素在使用者視角就形成了層疊的關系,某個元素可能覆寫了其他元素也可能被其他元素覆寫。

CSS 中重要的層疊概念

那麼這裡有幾個重要的概念:層疊上下文 (堆疊上下文 Stacking Context)、層疊等級 (層疊水準 Stacking Level)、層疊順序 (層疊次序、堆疊順序 Stacking Order)、z-index。

聲明:

1. 以下定位元素指的是 

position:absolute|fixed|relative|sticky

2. 以下非定位元素指的是 

position:initial|static

3. 關于層疊上下文還有一個類似的概念:塊級格式化上下文(BFC, Block Formatting Context),可以參考一下 CSS 中重要的BFC,其中還介紹了一些文檔流的内容

4. 本文蠻長的,但是如果你有勇氣看完,那應該對層疊有關概念就基本掌握了 (~o ̄▽ ̄)~

1. 層疊上下文 (Stacking Context)

層疊上下文 (堆疊上下文, Stacking Context),是HTML中一個三維的概念。在CSS2.1規範中,每個元素的位置是三維的,當元素發生層疊,這時它可能覆寫了其他元素或者被其他元素覆寫;排在z軸越靠上的位置,距離螢幕觀察者越近。

文章關于z-index 那些你不知道的事有一個很好的比喻,這裡引用一下。

可以想象一張桌子,上面有一堆物品,這張桌子就代表着一個層疊上下文。 如果在第一張桌子旁還有第二張桌子,那第二張桌子就代表着另一個層疊上下文。

現在想象在第一張桌子上有四個小方塊,他們都直接放在桌子上。 在這四個小方塊之上有一片玻璃,而在玻璃片上有一盤水果。 這些方塊、玻璃片、水果盤,各自都代表着層疊上下文中一個不同的層疊層,而這個層疊上下文就是桌子。

每一個網頁都有一個預設的層疊上下文。 這個層疊上下文(桌子)的根源就是

<html></html>

。 html标簽中的一切都被置于這個預設的層疊上下文的一個層疊層上(物品放在桌子上)。

當你給一個定位元素賦予了除

auto

外的 z-index 值時,你就建立了一個新的層疊上下文,其中有着獨立于頁面上其他層疊上下文和層疊層的層疊層, 這就相當于你把另一張桌子帶到了房間裡。

CSS 中重要的層疊概念

層疊上下文1 (Stacking Context 1)是由文檔根元素形成的, 層疊上下文2和3 (Stacking Context 2, 3) 都是層疊上下文1 (Stacking Context 1) 上的層疊層。 他們各自也都形成了新的層疊上下文,其中包含着新的層疊層。

在層疊上下文中,其子元素按照上面解釋的規則進行層疊。形成層疊上下文的方法有:

● 根元素 

<html></html>

● position

值為 

absolute|relative

,且 

z-index

值不為 

auto

● position

 值為 

fixed|sticky

● z-index

 值不為 

auto

 的flex元素,即:父元素 

display:flex|inline-flex

● opacity

 屬性值小于 

1

 的元素

● transform

 屬性值不為 

none

的元素

● mix-blend-mode

normal

● filter

、 

perspective

clip-path

mask

mask-image

mask-border

motion-path

none

● perspective

none

● isolation

 屬性被設定為 

isolate

● will-change

 中指定了任意 CSS 屬性,即便你沒有直接指定這些屬性的值

● -webkit-overflow-scrolling

 屬性被設定 

touch

總結:

1. 層疊上下文可以包含在其他層疊上下文中,并且一起組建了一個有層級的層疊上下文

2. 每個層疊上下文完全獨立于它的兄弟元素,當處理層疊時隻考慮子元素,這裡類似于BFC

3. 每個層疊上下文是自包含的:當元素的内容發生層疊後,整個該元素将會在父級疊上下文中按順序進行層疊

2. 層疊等級 (Stacking Level)

層疊等級 (層疊水準, Stacking Level) 決定了同一個層疊上下文中元素在z軸上的顯示順序的概念:

● 普通元素的層疊等級優先由其所在的層疊上下文決定

● 層疊等級的比較隻有在同一個層疊上下文元素中才有意義

● 在同一個層疊上下文中,層疊等級描述定義的是該層疊上下文中的元素在Z軸上的上下順序

注意,層疊等級并不一定由 z-index 決定,隻有定位元素的層疊等級才由 z-index 決定,其他類型元素的層疊等級由層疊順序、他們在HTML中出現的順序、他們的父級以上元素的層疊等級一同決定,詳細的規則見下面層疊順序的介紹。

3. z-index

在 CSS 2.1 中,所有的盒模型元素都處于三維坐标系中。 除了我們常用的橫坐标和縱坐标, 盒模型元素還可以沿着"z 軸"層疊擺放, 當他們互相覆寫時, z 軸順序就變得十分重要。

—— CSS 2.1 Section 9.9.1 - Layered presentation

z-index 隻适用于定位的元素,對非定位元素無效,它可以被設定為正整數、負整數、0、auto,如果一個定位元素沒有設定 z-index,那麼預設為auto。

元素的 z-index 值隻在同一個層疊上下文中有意義。如果父級層疊上下文的層疊等級低于另一個層疊上下文的,那麼它 z-index 設的再高也沒用。是以如果你遇到 z-index 值設了很大,但是不起作用的話,就去看看它的父級層疊上下文是否被其他層疊上下文蓋住了。

4. 層疊順序 (Stacking Order)

層疊順序 (層疊次序, 堆疊順序, Stacking Order) 描述的是元素在同一個層疊上下文中的順序規則,從層疊的底部開始,共有七種層疊順序:

1. 背景和邊框:形成層疊上下文的元素的背景和邊框。

2. 負z-index值:層疊上下文内有着負z-index值的定位子元素,負的越大層疊等級越低;

3. 塊級盒:文檔流中塊級、非定位子元素;

4. 浮動盒:非定位浮動元素;

5. 行内盒:文檔流中行内、非定位子元素;

6. z-index: 0:z-index為0或auto的定位元素, 這些元素形成了新的層疊上下文;

7.正z-index值:z-index 為正的定位元素,正的越大層疊等級越高;

同一個層疊順序的元素按照在HTML裡出現的順序層疊;第7級順序的元素會顯示在之前順序元素的上方,也就是看起來覆寫了更低級的元素:

CSS 中重要的層疊概念

5. 實戰

5.1 普通情況

三個

relative

定位的

div

塊中各有

absolute

的不同顔色的

span.red

span.green

span.blue

,它們都設定了

position:absolute

,參見Codepen - 普通情況。

那麼當沒有元素包含z-index屬性時,這個例子中的元素按照如下順序層疊(從底到頂順序):

1. 根元素的背景和邊界

2. 塊級非定位元素按HTML中的出現順序層疊

3. 行内非定位元素按HTML中的出現順序層疊

4. 定位元素按HTML中的出現順序層疊

紅綠藍都屬于 z-index 為auto的定位元素,是以按照7層層疊順序規則來說同屬于層疊順序第6級,是以按HTML中的出現順序層疊:

紅->綠->藍

5.2 在相同層疊上下文的父元素内的情況

紅綠位于一個

div.first-box

下,藍位于

div.second-box

下,紅綠藍都設定了

position:absolute

first-box

second-box

都設定了

position:relative

,參見Codepen - 父元素不同但都位于根元素下。

這個例子中,紅藍綠元素的父元素

first-box

second-box

都沒有生成新的層疊上下文,都屬于根層疊上下文中的元素,且都是層疊順序第6級,是以按HTML中的出現順序層疊:

紅->綠->藍

5.3 給子元素增加 z-index

div.first-box

下,藍黃位于

div.second-box

position:absolute

,如果這時給綠加一個屬性

z-index:1

,那麼此時

.green

位于最上面。

如果再在

.second-box

.green

後加一個絕對定位的

span.gold

,設定

z-index:-1

,那麼它将位于紅綠藍的下面,參見Codepen - 設定了z-index。

這個例子中,紅藍綠黃元素的父元素中都沒有生成新的層疊上下文,都屬于根層疊上下文中的元素:

1. 紅藍都沒有設定 z-index,同屬于層疊順序中的第6級,按HTML中的出現順序層疊。

2. 綠設定了正的 z-index,屬于第7級。

3. 黃設定了負的 z-index,屬于第2級。

是以這個例子中的從底到高顯示的順序就是:

黃->紅->藍->綠

5.4 在不同層疊上下文的父元素内的情況

div.first-box

div.second-box

position:absolute

,如果

first-box

的z-index設定的比

second-box

的大,那麼此時無論藍的 z-index 設定的多大

z-index:999

,藍都位于紅綠的下面;如果我們隻更改紅綠的z-index值,由于這兩個元素都在父元素

first-box

産生的層疊上下文中,此時誰的z-index值大,誰在上面,參見Codepen - 不同層疊上下文的父元素。

這個例子中,紅綠藍都屬于設定了z-index的定位元素,不過他們的父元素建立了新的層疊上下文:

1. 紅綠的父元素 

first-box

是設定了正z-index的定位元素,是以建立了一個層疊上下文,屬于層疊順序中的第7級。

2. 藍的父元素 

second-box

也同樣建立了一個層疊上下文,屬于層疊順序中的第6級。

3. 按照層疊順序, 

first-box

中所有元素都排在 

second-box

上。

4. 紅綠都屬于層疊上下文 

first-box

中且設定了不同的正 z-index,都屬于層疊順序中第7級。

5. 藍屬于層疊上下文 

second-box

,且設定了一個很大的正 z-index,屬于層疊元素中第7級。

6. 雖然藍的 z-index 很大,但是因為 

second-box

的層疊等級比 

first-box

小,是以位于紅綠之下。

是以這個例子中從低到到顯示的順序:

藍->紅->綠

(我遇到的的情況就屬于這個例子類似情形)。

5.5 給子元素設定 opacity

紅綠位于

div.first-box

div.second-box

position:absolute

,綠設定了

z-index:1

,那麼此時綠位于紅藍的最上面。

如果此時給

first-box

設定

opacity:.99

,這時無論紅綠的 z-index 設定的多大

z-index:999

,藍都位于紅綠的上面。

.second-box

.green

後加一個

span.gold

z-index:-1

,那麼它将位于紅綠藍的下面,參見Codepen - opacity的影響。

之前已經介紹了,設定

opacity

也可以形成層疊上下文,是以:

1. 

first-box

設定了 

opacity

, 

first-box

成為了一個新的層疊上下文。

2. second-box

沒有形成新的層疊上下文,是以其中的元素都屬于根層疊上下文。

3.  黃屬于層疊順序中第2級,紅綠屬于第7級, 

first-box

屬于第6級,藍屬于層疊順序中第6級且按HTML出現順序位于 

first-box

之上。

黃->紅->綠->藍

網上的文章大多深淺不一,甚至有些前後沖突,在下的文章都是學習過程中的總結,如果發現錯誤,歡迎留言指出~

參考

1. 你不知道的Z-Index

2. MDN - z-index

3. What No One Told You About Z-Index

4. 徹底搞懂CSS層疊上下文、層疊等級、層疊順序、z-index

5. 前端性能優化之更平滑的動畫

6. 關于z-index 那些你不知道的事

7. 聊聊CSS中的層疊相關概念

原文釋出時間為:2018-09-28

本文作者:SHERlocked93

本文來自雲栖社群合作夥伴“

前端大學

”,了解相關資訊可以關注“