想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等着你!css
z-index
屬性,儘管已經寫了這麼多,仍然被普遍地誤解和錯誤地處理。在複雜的單頁web應用程序中堆積問題可能會成爲一個主要問題。然而,堅持一些原則,咱們能夠很容易地避免這些問題。html
若是你有過任何複雜的Web UI開發,那麼你可能有些時候會瘋狂地嘗試將元素的 z-index
設置爲上千或者很大的一個數,卻發現它不能幫助你把它放在其餘元素之上,這些元素的z-index
更低,甚至根本沒有定義。前端
爲何會這樣?更重要的是,如何避免這些問題?git
在本文中,我將講述z-index
其實是什麼,以及如何中止猜想它是否適用於任何特定的狀況,並開始像對待任何其餘方便的工具同樣對待它。github
層疊上下文的層次結構web
若是你把網頁想象成三維的,那麼z-index
是定義了一個元素的z
座標(也稱爲它的層疊順序)屬性:值越大,元素離觀察者越近。你也能夠將它看做是影響繪製順序的屬性,由於屏幕是由像素組成的二維網格。所以,z-index
值越大,元素在頁面上繪製的時間就越晚。segmentfault
然而,一個主要的複雜因素是 z-index
值空間不平 - 它是分層的。 元素能夠建立層疊上下文,該上下文成爲其後代的z-index
值的根。 接着經過一個例子來解釋層疊上下文的概念。架構
文檔正文有五個div
節點:div1
,div2
,div3
,div1-1
和div2-1
。 它們都是絕對定位的而且彼此重疊。 div1-1
是div1
的子節點,div2-1
是div2
的子節點。ide
<body> <div class="div1"> <strong>div1</strong> <br/> (z-index: auto) <div class="div1-1"> <strong>div1-1</strong> <br/> (z-index: 10) </div> </div> <div class="div2"> <strong>div2</strong> <br/> (z-index: 1) <div class="div2-1"> <strong>div2-1</strong> <br/> (z-index: 10) </div> </div> <div class="div3"> <strong>div3</strong> <br/> (z-index: 2) </div> </body>
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
值相同,那麼在樣式文件中出現越靠後,繪製越晩。
所以,根據咱們的 CSS 文件,若是咱們不考慮層疊上下文,順序應該以下:
注意,div2-1
實際上位於 div3
後面的,爲何會這樣?
注意:z-index 值爲 auto 不會建立一個 層疊上下文
若是一個元素要建立一個層疊上下文,它會爲其子元素的 z-index
值建立一個地基或者局部框,所以在肯定繪製順序時,它們永遠不會與層疊上下文以外的任何內容進行比較。 換句話說,當一個建立層疊上下文的元素被繪製時,這個元素下的的全部子元素都在它以後和它的任何兄弟以前繪製。
回到示例,body 後代div
的實際繪製順序是
注意列表中沒有 div2-1
,它是div2
的一個子元素,它建立了一個層疊上下文(由於它是一個絕對定位的元素,除了auto
的默認值以外,它還有z-index
),因此它是在div2
以後繪製的,但在div3
以前。
div1
沒有建立層疊上下文,由於它的z-index
值爲 auto
,因此在div2
和div3
以後繪製div1-1
(div1的子元素,由於div1-1
的 z-index
值爲 10
大於 div2
和 div3
。
若是你沒有看懂,請不要擔憂。如下是一些資源能夠更好地解釋這些概念:
然而,本文的重點是,當頁面由數十個和數百個組件組成時,如何處理z-index
,每一個組件均可能定義了z-index
的子組件。
關於z-index
最流行的一篇文章建議將全部z-index值分組在一個地方,可是若是這些值不屬於相同的層疊上下文(在大型應用程序中可能不容易實現),那麼比較這些值就沒有意義了。
這裏一個例子。 假設咱們有一個包含 header
和 main
部分的頁面。 因爲某種緣由,main 裏面內容樣式必須設置:position: relative
和 z-index: 1
。
// html <div class="header"> Header </div> <div class="main"> Main Content </div>
// 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
// html <div class="header"> Header <div class="overlay"> Overlay </div> </div> <div class="main"> Main Content </div>
// 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元素相關聯的計算來講是很划算的,節省開發人員在處理層疊上下文問題時間。
// html <!-- root component starts --> <div class="root__container"> <div class="root__header"> <!-- header component starts --> <div class="header__container"> Header <div class="header__overlay"> Overlay </div> </div> <!-- header component ends --> </div> <div class="root__main"> <!-- main component starts --> <div class="main__container"> Main Content </div> <!-- main component ends --> </div> </div> <!-- root component ends -->
// 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
內建立此類疊加層:
// html <div class="header"> Header <div class="header-overlay"> Header Overlay </div> </div> <div class="main"> Main Content <div class="main-overlay"> Main Overlay </div> </div>
// 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
值,則沒必要執行此操做;10
的步長,或者你可使用變量——這都取決於你的項目約定和組件的大小。最好只將z-index
分配給同級元素。不然,你可能會無心中在一個組件中引入更多的層疊上下文。z-index
。你的點贊是我持續分享好東西的動力,歡迎點贊!