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