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