摘要:接著我們解釋我們所看到的現象。刪除上述所說的運行效果這種架構并非沒有缺點。例如,你將無法在和內創建此類疊加層查看示例然而,根據我的經驗,這很少是一個問題。找到兩個沒有正確層疊的元素的第一個祖先組件,并根據需要更改該組件中的。
想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你!
z-index 屬性,盡管已經寫了這么多,仍然被廣泛地誤解和錯誤地處理。在復雜的單頁web應用程序中堆積問題可能會成為一個主要問題。然而,堅持一些原則,我們可以很容易地避免這些問題。
如果你有過任何復雜的Web UI開發,那么你可能有些時候會瘋狂地嘗試將元素的 z-index 設置為上千或者很大的一個數,卻發現它不能幫助你把它放在其他元素之上,這些元素的z-index更低,甚至根本沒有定義。
為什么會這樣?更重要的是,如何避免這些問題?
在本文中,我將講述z-index實際上是什么,以及如何停止猜測它是否適用于任何特定的情況,并開始像對待任何其他方便的工具一樣對待它。
層疊上下文的層次結構
如果你把網頁想象成三維的,那么z-index是定義了一個元素的z坐標(也稱為它的層疊順序)屬性:值越大,元素離觀察者越近。你也可以將它看作是影響繪制順序的屬性,因為屏幕是由像素組成的二維網格。因此,z-index 值越大,元素在頁面上繪制的時間就越晚。
然而,一個主要的復雜因素是 z-index 值空間不平 - 它是分層的。 元素可以創建層疊上下文,該上下文成為其后代的z-index值的根。 接著通過一個例子來解釋層疊上下文的概念。
文檔正文有五個div節點:div1,div2,div3,div1-1和div2-1。 它們都是絕對定位的并且彼此重疊。 div1-1是div1的子節點,div2-1是div2的子節點。
htmlcssdiv1
(z-index: auto)div1-1
(z-index: 10)div2
(z-index: 1)div2-1
(z-index: 10)div3
(z-index: 2)
div { box-sizing: border-box; border: 1px solid black; padding: 5px; position: absolute; font-family: Verdana; } .div1, .div2, .div3 { width: 500px; height: 200px; } .div1-1, .div2-1 { width: 200px; height: 150px; } .div1 { left: 10px; top: 10px; background-color: rgba(220, 220, 170, 0.9); } .div1-1 { left: 250px; top: 30px; background-color: rgba(220, 170, 170, 0.9); z-index: 10; } .div2 { left: 20px; top: 90px; background-color: rgba(220, 170, 220, 0.9); z-index: 1; } .div2-1 { left: 120px; top: 30px; background-color: rgba(170, 220, 170, 0.9); z-index: 10; } .div3 { left: 30px; top: 170px; background-color: rgba(170, 220, 220, 0.9); z-index: 2; }
接著我們解釋我們所看到的現象。這里有詳細繪制順序,但這里我們只需要比較兩件事。
z-index 值
如果元素具有更高的z-index,則繪制會比值小的晚。
樣式資源順序
如果 z-index 值相同,那么在樣式文件中出現越靠后,繪制越晩。
因此,根據我們的 CSS 文件,如果我們不考慮層疊上下文,順序應該如下:
div1
div2
div3
div1-1
div2-1
注意,div2-1 實際上位于 div3 后面的,為什么會這樣?
注意:z-index 值為 auto 不會創建一個 層疊上下文
如果一個元素要創建一個層疊上下文,它會為其子元素的 z-index值創建一個地基或者局部框,因此在確定繪制順序時,它們永遠不會與層疊上下文之外的任何內容進行比較。 換句話說,當一個創建層疊上下文的元素被繪制時,這個元素下的的所有子元素都在它之后和它的任何兄弟之前繪制。
回到示例,body 后代div的實際繪制順序是
div1
div2
div3
div1-1
注意列表中沒有 div2-1,它是div2的一個子元素,它創建了一個層疊上下文(因為它是一個絕對定位的元素,除了auto的默認值之外,它還有z-index),所以它是在div2之后繪制的,但在div3之前。
div1 沒有創建層疊上下文,因為它的z-index 值為 auto,所以在div2和div3之后繪制div1-1(div1的子元素,因為div1-1的 z-index 值為 10 大于 div2 和 div3。
如果你沒有看懂,請不要擔心。以下是一些資源可以更好地解釋這些概念:
“The Stacking Context” MDN 文檔
“What No One Told You About Z-Index” Philip Walton
然而,本文的重點是,當頁面由數十個和數百個組件組成時,如何處理z-index,每個組件都可能定義了z-index的子組件。
關于z-index 最流行的一篇文章建議將所有z-index值分組在一個地方,但是如果這些值不屬于相同的層疊上下文(在大型應用程序中可能不容易實現),那么比較這些值就沒有意義了。
這里一個例子。 假設我們有一個包含 header和 main 部分的頁面。 由于某種原因,main 里面內容樣式必須設置:position: relative 和 z-index: 1。
// htmlHeaderMain Content
// css body { margin: 0; font-family: Verdana; text-align: center; background-color: white; } div { display: flex; align-items: center; justify-content: center; } .header { background-color: rgba(255, 255, 220, 0.5); font-size: 10vmin; position: relative; height: 30vh; } .main { background-color: rgba(220, 255, 255, 0.5); font-size: 10vmin; height: 70vh; position: relative; z-index: 1; }
運行效果:
查看示例
在這里使用的是組件體系結構,所以根組件和每個子組件的 CSS 都是在專用部分中定義的。實際上,組件將駐留在多帶帶的文件中,并且標記將使用你選擇的 JavaScript 庫(如React)生成,但出于演示目的,將所有內容放在一起也沒有問題。
現在,假設我們的任務是在header中創建一個下拉菜單。當然,它必須位于main上面,所以我們給它一個z-index:10
// htmlHeaderMain Content
// css body { margin: 0; font-family: Verdana; text-align: center; background-color: white; } div { display: flex; align-items: center; justify-content: center; } .header { background-color: rgba(255, 255, 220, 0.8); font-size: 10vmin; position: relative; height: 30vh; } .overlay { position: absolute; z-index: 10; background-color: rgba(255, 220, 255, 0.8); left: 10vw; top: 25vh; width: 50vw; height: 50vh; filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.3)); } .overlay::after { content: ""; position: absolute; left: 50%; transform: translateX(-50%); bottom: 100%; width: 0; height: 0; border-top: 10px solid transparent; border-right: 10px solid transparent; border-left: 10px solid transparent; border-bottom: 10px solid rgba(255, 220, 255, 0.8); } .main { background-color: rgba(220, 255, 255, 0.8); font-size: 10vmin; height: 70vh; position: relative; z-index: 1; }
運行效果:
查看示例
現在,幾個月后,為了讓一些不相關的東西更好地工作,我們需要在 header 樣式多加一個 transform: translateZ(0)。
// 部分代碼 .header { background-color: rgba(255, 255, 220, 0.8); font-size: 10vmin; position: relative; height: 30vh; transform: translateZ(0); }
如你所見,布局現已被打破。 在沒有z-index規則的情況下,z-index:1的元素位于具有z-index:10的元素的頂部。 原因是header使用transform屬性 它創建了一個層疊上下文,默認會有自己的z-index,值為0 低于 main 中 z-index (1)。
解決方案很簡單:給header一個z-index值為2。
// 部分代碼 .header { background-color: rgba(255, 255, 220, 0.8); font-size: 10vmin; position: relative; height: 30vh; transform: translateZ(0); z-index: 2; }
運行效果:
查看示例
問題是,如果我們在組件內的組件中有組件,每個組件具有不同的z-index元素,我們應該怎么做到這個解決方案? 我們如何確保更改 header 的z-index不會破壞其他任何內容?
答案是需要一種協定,消除了猜測的需要,它是這樣的:更改組件內的z-index應該只影響該組件,而不影響其他任何東西。換句話說,在處理某個CSS文件中的z-index值時,理想情況下我們應該只關心該文件中的其他值。
實現它很容易。 我們應該簡單地確保每個組件的根創建層疊上下文。 最簡單的方法是為它提供鵲確切的 position 和 z-index 的值,而不是使用默認它們自己的默認值。
下面是構建應用程序的一種方法。它使用的元素比前一個多,但是相對額外的DOM元素相關聯的計算來說是很劃算的,節省開發人員在處理層疊上下文問題時間。
// htmlHeaderMain Content
// css body { margin: 0; font-family: Verdana; text-align: center; background-color: white; } /* Root styles */ .root__container { position: relative; z-index: 0; } .root__header { position: relative; z-index: 2; } .root__main { position: relative; z-index: 1; } /* Header styles */ .header__container { background-color: rgba(255, 255, 220, 0.8); font-size: 10vmin; position: relative; height: 30vh; transform: translateZ(0); display: flex; align-items: center; justify-content: center; z-index: 0; } .header__overlay { position: absolute; z-index: 1; background-color: rgba(255, 220, 255, 0.8); left: 10vw; top: 25vh; width: 50vw; height: 50vh; filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.3)); display: flex; align-items: center; justify-content: center; } .header__overlay::after { content: ""; position: absolute; left: 50%; transform: translateX(-50%); bottom: 100%; width: 0; height: 0; border-top: 10px solid transparent; border-right: 10px solid transparent; border-left: 10px solid transparent; border-bottom: 10px solid rgba(255, 220, 255, 0.8); } /* Main section styles */ .main__container { background-color: rgba(220, 255, 255, 0.8); font-size: 10vmin; height: 70vh; display: flex; align-items: center; justify-content: center; position: relative; z-index: 0; }
運行效果:
查看示例
header__container 和 main__container 都有 position: relative和z-index: 0
header overlay現有z-index: 1(我們不需要很大的值,因為它只會與 header 中的其他元素進行比較)
root__header 現有z-index: 2,而 root__main 保持其z-index: 1,這就是兩兄弟正確層疊的原因
(還要注意,兩者都有position: relative,因為 z-index 不適用于 position:static的元素。)
如果我們現在查看 header 代碼,我們會注意到我們可以完全從container和 overlay 層中刪除z-index屬性,因為overlay 層是那里唯一定位的元素。 同樣,main container 上不需要z-index。 這樣分類最大好處:在查看z-index時,只注重組件本身,而不是它的上下文。
// 刪除上述所說的 z-index body { margin: 0; font-family: Verdana; text-align: center; background-color: white; } /* Root styles */ .root__container { position: relative; z-index: 0; } .root__header { position: relative; z-index: 2; } .root__main { position: relative; z-index: 1; } /* Header styles */ .header__container { background-color: rgba(255, 255, 220, 0.8); font-size: 10vmin; position: relative; height: 30vh; transform: translateZ(0); display: flex; align-items: center; justify-content: center; } .header__overlay { position: absolute; background-color: rgba(255, 220, 255, 0.8); left: 10vw; top: 25vh; width: 50vw; height: 50vh; filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.3)); display: flex; align-items: center; justify-content: center; } .header__overlay::after { content: ""; position: absolute; left: 50%; transform: translateX(-50%); bottom: 100%; width: 0; height: 0; border-top: 10px solid transparent; border-right: 10px solid transparent; border-left: 10px solid transparent; border-bottom: 10px solid rgba(255, 220, 255, 0.8); } /* Main section styles */ .main__container { background-color: rgba(220, 255, 255, 0.8); font-size: 10vmin; height: 70vh; display: flex; align-items: center; justify-content: center; }
運行效果:
這種架構并非沒有缺點。 它以犧牲一些靈活性為代價使應用程序更具可預測性。 例如,你將無法在header和main section內創建此類疊加層:
// htmlHeaderMain Content
// css body { margin: 0; font-family: Verdana; text-align: center; background-color: white; } div { display: flex; align-items: center; justify-content: center; } .header { background-color: rgba(255, 255, 220, 0.8); font-size: 10vmin; position: relative; height: 30vh; } .header-overlay { position: absolute; z-index: 10; background-color: rgba(255, 220, 255, 0.8); left: 2vw; top: 25vh; width: 47vw; height: 50vh; filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.3)); } .header-overlay::after { content: ""; position: absolute; left: 50%; transform: translateX(-50%); bottom: 100%; width: 0; height: 0; border-top: 10px solid transparent; border-right: 10px solid transparent; border-left: 10px solid transparent; border-bottom: 10px solid rgba(255, 220, 255, 0.8); } .main { background-color: rgba(220, 255, 255, 0.8); font-size: 10vmin; height: 70vh; position: relative; } .main-overlay { position: absolute; z-index: 10; background-color: rgba(255, 255, 255, 0.8); left: 51vw; bottom: 40vh; width: 47vw; height: 50vh; filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.3)); } .main-overlay::after { content: ""; position: absolute; left: 50%; transform: translateX(-50%); top: 100%; width: 0; height: 0; border-top: 10px solid rgba(255, 255, 255, 0.8); border-right: 10px solid transparent; border-left: 10px solid transparent; border-bottom: 10px solid transparent; }
查看示例
然而,根據我的經驗,這很少是一個問題。 你可以使用 main section 中的 overlay 層向下而不是向上,以使其不與header相交。 或者,如果你真的需要它,你可以在正文的末尾注入疊加HTML 并給它一個大的 z-index 值(“大”是比頂層其他部分更大)。
再次說明
通過使每個組件的根成為層疊上下文,根據元素的z-index值隔離組件;
如果組件中的元素不需要除auto之外的z-index值,則不必執行此操作;
在組件的 CSS 文件中,可以以你喜歡的方式維護z索引值。它可能是連續的值,或者你可以給它們一個10的步長,或者你可以使用變量——這都取決于你的項目約定和組件的大小。最好只將z-index分配給同級元素。否則,你可能會無意中在一個組件中引入更多的層疊上下文。
調試變得容易。找到兩個沒有正確層疊的元素的第一個祖先組件,并根據需要更改該組件中的z-index。
你的點贊是我持續分享好東西的動力,歡迎點贊!
歡迎加入前端大家庭,里面會經常分享一些技術資源。文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104021.html
摘要:接著我們解釋我們所看到的現象。刪除上述所說的運行效果這種架構并非沒有缺點。例如,你將無法在和內創建此類疊加層查看示例然而,根據我的經驗,這很少是一個問題。找到兩個沒有正確層疊的元素的第一個祖先組件,并根據需要更改該組件中的。 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! z-index 屬性,盡管已經寫了這么多,仍然被廣泛地誤解和錯誤地處理。在復雜的單頁web應...
摘要:最近是用開發了一套組件庫在開發過程對對于組件化的開發有一些感想,于是開始記錄下這些。彈窗組件一直是開發中必備的,使用頻率相當高,最常見的莫過于,,這些曾經我們都會用來調試程序不同的組件庫對于彈窗的處理也是不一樣的。 最近是用 vue 開發了一套組件庫 vue-carbon , 在開發過程對對于組件化的開發有一些感想,于是開始記錄下這些。 彈窗組件一直是 web 開發中必備的,使用頻率相...
摘要:前后端都要關注注入攻擊跨站腳本攻擊跨站請求偽造開放重定向這些安全性問題。前端也需要構建自動化測試,包括獨立單元測試和端到端測試自動化,當然還有人工測試。 總體指導思想是前后端分離,后端同事提供線上API數據查詢接口或websocket接口,前端同事負責處理獲取到的數據、編寫展示的頁面、實現用戶交互;前后端都要考慮web開發的安全性問題,表單提交到數據庫前對用戶的輸入進行轉義、登錄避免明...
摘要:前后端都要關注注入攻擊跨站腳本攻擊跨站請求偽造開放重定向這些安全性問題。前端也需要構建自動化測試,包括獨立單元測試和端到端測試自動化,當然還有人工測試。 總體指導思想是前后端分離,后端同事提供線上API數據查詢接口或websocket接口,前端同事負責處理獲取到的數據、編寫展示的頁面、實現用戶交互;前后端都要考慮web開發的安全性問題,表單提交到數據庫前對用戶的輸入進行轉義、登錄避免明...
閱讀 3077·2019-08-30 15:56
閱讀 1234·2019-08-29 15:20
閱讀 1571·2019-08-29 13:19
閱讀 1473·2019-08-29 13:10
閱讀 3381·2019-08-26 18:27
閱讀 3069·2019-08-26 11:46
閱讀 2234·2019-08-26 11:45
閱讀 3753·2019-08-26 10:12