CSS 中重要的層疊概念

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

屏幕是一個二維平面,然而HTML元素倒是排列在三維座標系中,x爲水平位置,y爲垂直位置,z爲屏幕由內向外方向的位置,咱們在看屏幕的時候是沿着z軸方向從外向內的;由此,元素在用戶視角就造成了層疊的關係,某個元素可能覆蓋了其餘元素也可能被其餘元素覆蓋;html

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

聲明:web

  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軸越靠上的位置,距離屏幕觀察者越近segmentfault

文章<關於z-index 那些你不知道的事>有一個很好的比喻,這裏引用一下;性能優化

能夠想象一張桌子,上面有一堆物品,這張桌子就表明着一個層疊上下文。 若是在第一張桌子旁還有第二張桌子,那第二張桌子就表明着另外一個層疊上下文。微信

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

每個網頁都有一個默認的層疊上下文。 這個層疊上下文(桌子)的根源就是<html></html>。 html標籤中的一切都被置於這個默認的層疊上下文的一個層疊層上(物品放在桌子上)。性能

當你給一個定位元素賦予了除 auto 外的 z-index 值時,你就建立了一個新的層疊上下文,其中有着獨立於頁面上其餘層疊上下文和層疊層的層疊層, 這就至關於你把另外一張桌子帶到了房間裏。學習

層疊上下文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 的元素
  • filterperspectiveclip-pathmaskmask-imagemask-bordermotion-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級順序的元素會顯示在以前順序元素的上方,也就是看起來覆蓋了更低級的元素:

5. 實戰

5.1 普通狀況

三個relative定位的div塊中各有absolute的不一樣顏色的span.redspan.greenspan.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: absolutefirst-boxsecond-box都設置了position: relative

參見Codepen - 父元素不一樣但都位於根元素下

這個例子中,紅藍綠元素的父元素first-boxsecond-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設置了opacityfirst-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中的層疊相關概念

推介閱讀:

  1. CSS 中重要的BFC

PS:歡迎你們關注個人公衆號【前端下午茶】,一塊兒加油吧~

另外能夠加入「前端下午茶交流羣」微信羣,長按識別下面二維碼便可加我好友,備註加羣,我拉你入羣~

相關文章
相關標籤/搜索