您是否曾經在 CSS 中的某個元素上設定了 z-index: 99999,並且它沒有出現在其他元素之上?假設所有不同的元素都設置為較低的值或根本沒有設置,那麼大的值應該很容易將該元素視覺地放置在其他元素之上。 網頁通常表示在二維空間中;然而,透過應用特定的 CSS 屬性,引入了一個假想的 z 軸平面來傳達深度。該平面垂直於螢幕,使用者可以從該平面感知元素的順序,一個在另一個之上。假想的 z 軸(使用者對堆疊元素的感知)背後的想法是,創建它的 CSS 屬性組合在一起形成我們所說的堆疊上下文。 我們將討論元素如何在網頁上「堆疊」、控制堆疊順序的因素以及在需要時「取消堆疊」元素的實用方法。 關於堆疊上下文 將您的網頁想像成一張桌子。當您加入 HTML 元素時,您會將一張張紙一張一張地放在桌上。最後放置的紙張相當於最近新增的 HTML 元素,並且它位於先前放置的所有其他紙張之上。這是正常的文檔流,即使對於嵌套元素也是如此。桌面本身代表根堆疊上下文,由 元素形成,其中包含所有其他資料夾。 現在,特定的 CSS 屬性開始發揮作用。 位置(帶有 z 索引)、不透明度、變換和包含等屬性就像資料夾一樣。這個資料夾採用一個元素及其所有子元素,從主堆疊中提取它們,並將它們分組到一個單獨的子堆疊中,創建我們所說的堆疊上下文。對於定位元素,當我們聲明 auto 以外的 z-index 值時,就會發生這種情況。對於不透明度、變換和過濾器等屬性,當套用特定值時會自動建立堆疊上下文。

試著理解這一點:一旦一張紙(即子元素)位於資料夾(即父元素的堆疊上下文)內,它就永遠無法退出該資料夾或放置在不同資料夾中的紙之間。它的 z-index 現在僅在其自己的資料夾內相關。

在下圖中,紙張 B 現在位於資料夾 B 的堆疊上下文中,並且只能與資料夾中的其他紙張一起訂購。

如果你願意的話,想像一下您的桌上有兩個資料夾:

資料夾 A
資料夾 B

.folder-a { z 索引: 1; } .folder-b { z 索引: 2; }

讓我們稍微更新一下標記。資料夾 A 內部是一個特殊頁面,z-index:9999。資料夾 B 內部是一個普通頁面,z-index:5。

特殊頁面

普通頁面

.special-page { z-index:9999; } .plain-page { z 索引: 5; }

哪一頁在最上面? 它是資料夾 B 中的 .plain-page。瀏覽器會忽略子檔案並先堆疊兩個資料夾。它看到資料夾 B (z-index: 2) 並將其放置在資料夾 A (z-index: 1) 的頂部,因為我們知道 2 大於 1。同時,設定為 z-index: 9999 的 .special-page 頁面位於堆疊底部,即使其 z-index 設定為可能的最高值。 堆疊上下文也可以嵌套(資料夾內的資料夾),建立「家譜」。同樣的原則也適用:孩子永遠無法逃脫父母的資料夾。 現在您已經了解了堆疊上下文的行為類似於對圖層進行分組和重新排序的資料夾,那麼值得一問的是:為什麼某些屬性(例如變換和不透明度)會建立新的堆疊上下文? 事情是這樣的:這些屬性不會因為它們的外觀而創建堆疊上下文;他們這樣做是因為瀏覽器在幕後的工作方式。當您應用變換、不透明度、濾鏡或透視時,您是在告訴瀏覽器:“嘿,這個元素可能會移動、旋轉或淡出,所以請做好準備!”

當您使用這些屬性時,瀏覽器會建立一個新的堆疊上下文來更有效地管理渲染。這允許瀏覽器獨立處理動畫、轉換和視覺效果,從而減少重新計算這些元素如何與頁面其餘部分互動的需要。可以把它想像成瀏覽器在說:“我將單獨處理這個文件夾,這樣我就不必在每次其中的內容髮生變化時重新調整整個桌面。” 但有副作用。一旦瀏覽器將一個元素提升到自己的層中,它必須「展平」其中的所有內容,創建一個新的堆疊上下文。這就像把一個資料夾從桌子上拿下來單獨處理一樣;該資料夾中的所有內容都會被分組,瀏覽器現在在決定哪些內容位於哪些內容之上時將其視為一個單元。 因此,即使變換和不透明度屬性似乎不會影響元素在視覺上堆疊的方式,但它們確實會影響,而且這是為了性能優化。出於類似的原因,其他幾個 CSS 屬性也可以建立堆疊上下文。如果您想深入了解,MDN 提供了完整的清單。有相當多,這只是說明了在不知情的情況下無意中創建堆疊上下文是多麼容易。 「拆垛」問題 出現堆疊問題的原因有很多,但有些原因比其他原因更常見。模態組件是一種經典模式,因為它們需要將組件切換為在所有其他元素上方的頂層“打開”,然後在“關閉”時將其從頂層刪除。 我非常有信心,我們所有人都遇到過這樣的情況:我們打開了一個模式,但無論出於何種原因,它都沒有出現。並不是它沒有正確打開,而是它在堆疊上下文的較低層中看不見。 這讓你想知道「怎麼會這樣?」自從你設定:

.覆蓋{ 位置:固定; /* 建立堆疊上下文 */ z 索引:1; /* 將元素放在其他所有元素之上的層上 */ 圖解:0; 寬度:100%; 高度:100vh; 溢出:隱藏; 背景顏色:#00000080; }

這看起來是正確的,但如果包含模態觸發器的父元素是另一個也設定為 z-index: 1 的父元素中的子元素,從技術上講,這會將模態放置在被主資料夾遮擋的子圖層中。讓我們看看這個特定場景和其他幾個常見的堆疊上下文陷阱。我想您不僅會看到無意中創建堆疊上下文是多麼容易,還會看到如何錯誤地管理它們。此外,如何返回託管狀態取決於具體情況。 場景 1:受困模態框

您可以立即看到困在低層中的模態並識別父模態。 瀏覽器擴充 聰明的開發人員已經建立了擴充功能來提供幫助。像是「CSS Stacking Context Inspector」這樣的工具 Chrome 擴充功能會在您的 DevTools 中新增一個額外的 z-index 選項卡,以向您顯示有關建立堆疊上下文的元素的資訊。

IDE 擴充 您甚至可以使用 VS Code 之類的擴充功能來發現開發過程中的問題,該擴充功能可以直接在編輯器中突出顯示潛在的堆疊上下文問題。

解除堆疊並重新獲得控制 確定根本原因後,下一步就是處理它。您可以採取多種方法來解決這個問題,我將按順序列出它們。不過,你可以選擇任何級別的任何人;任何人都不能抱怨或阻礙他人。 變更 HTML 結構 這被認為是最佳修復。為了讓您遇到堆疊上下文問題,您必須將一些元素放置在 HTML 中有趣的位置。重構頁面將幫助您重塑 DOM 並消除堆疊上下文問題。找到有問題的元素並將其從 HTML 標記中的捕獲元素中刪除。例如,我們可以透過將 .modal-container 從標頭中移出並將其單獨放置在 元素中來解決第一個場景「陷阱模態」。

<標題類別=“標題”>

標題

<主類別=“內容”>

主要內容

此內容的 z 索引為 2,但仍不會覆寫模態框。

當您按一下「開啟模態」按鈕時,模態將會按預期放置在其他所有內容的前面。 請參閱 Shoyombo Gabriel Ayomide 的鋼筆場景 1:受困模態(解決方案)[forked]。 調整CSS 中的父堆疊上下文 如果您無法在不破壞佈局的情況下移動該元素怎麼辦?最好解決這個問題:父母建立上下文。尋找負責觸發上下文的 CSS 屬性(或多個屬性)並將其刪除。如果它有目的且無法刪除,請為父級賦予比其兄弟元素更高的 z-index 值,以提升整個容器。 z-index 值較高時,父容器會移至頂部,其子容器會顯得更靠近使用者。 根據我們在「淹沒的下拉式選單」場景中學到的知識,我們無法將下拉式選單移出導覽列;這沒有意義。但是,我們可以將 .navbar 容器的 z-index 值增加到大於 .content 元素的 z-index 值。 .導覽列{ 背景:#333; /* z 索引: 1; */ z 索引:3; 位置:相對; }

透過此更改,.dropdown-menu 現在顯示在內容前面,沒有任何問題。 請參閱 Shoyombo Gabriel Ayomide 的鋼筆場景 2:淹沒下拉選單(解決方案)[forked]。 如果使用框架,請嘗試門戶 在 React 或 Vue 等框架中,Portal 是一項功能,可讓您在 DOM 中正常父層次結構之外渲染元件。門戶就像組件的傳送設備。它們允許您在文件中的任何位置渲染元件的 HTML(通常在 document.body 中),同時保持其與原始父級的 props、state 和 events 的邏輯連接。這非常適合逃避堆疊上下文陷阱,因為渲染的輸出實際上出現在有問題的父容器之外。 ReactDOM.createPortal( <工具提示/>, 文件正文 );

這可以確保您的下拉內容不會隱藏在其父級後面,即使父級具有溢出:隱藏或較低的 z-index 也是如此。 在我們之前看到的「剪下工具提示」場景中,我使用 Portal 將工具提示從溢出:隱藏剪輯中拯救出來,方法是將其放置在文件正文中並將其放置在容器內觸發器上方。 請參閱 Shoyombo Gabriel Ayomide 的鋼筆場景 3:剪輯的工具提示(解決方案)[forked]。 引入無副作用的堆疊上下文 上一節中解釋的所有方法都旨在從有問題的堆疊上下文中「拆開」元素,但在某些情況下您實際上需要或想要建立堆疊上下文。 建立新的堆疊上下文很容易,但所有方法都會產生副作用。即,除了使用隔離:isolate。當應用於元素時,該元素的子元素的堆疊上下文是相對於每個子元素並在該上下文內確定的,而不是受到其外部元素的影響。一個典型的例子是為該元素分配負值,例如 z-index: -1。 假設您有一個 .card 組件。您想要新增位於 .card 文字後面、卡片背景之上的裝飾形狀。如果卡片上沒有堆疊上下文,z-index: -1 會將形狀傳送到根堆疊上下文(整個頁面)的底部。這使得它消失在 .card 的白色背景後面: 請參閱 Shoyombo Gabriel Ayomide 的 Pen Negative z-index(問題)[forked]。 為了解決這個問題,我們在父親 .card 上聲明隔離:isolate: 請參閱 Shoyombo Gabriel Ayomide 的 Pen Negative z-index(解決方案)[forked]。 現在,.card 元素本身成為堆疊上下文。當它的子元素(在 :before 偽元素上建立的裝飾形狀)的 z-index: -1 時,它會轉到父級堆疊上下文的最底部。正如預期的那樣,它完美地位於文字後面和卡片背景的頂部。 結論 請記住:下次當你的 z-index 看起來失控時,它就是一個被困的堆疊上下文。 參考文獻

堆疊上下文 (MDN) Z-index 和堆疊上下文 (web.dev) “如何使用 CSS 中的隔離屬性創建新的堆疊上下文”,Natalie Pina “到底是什麼,z-index?”,喬許·科莫

進一步閱讀 SmashingMag

“在大型專案中管理 CSS Z-Index”,Steven Frieson “黏性標題和全高元素:一個棘手的組合”,Philip Braunen “在基於元件的 Web 應用程式中管理 Z-Index”,Pavel Pomerantsev “Z-Index CSS 屬性:全面了解”,Louis Lazaris

You May Also Like

Enjoyed This Article?

Get weekly tips on growing your audience and monetizing your content — straight to your inbox.

No spam. Join 138,000+ creators. Unsubscribe anytime.

Create Your Free Bio Page

Join 138,000+ creators on Seemless.

Get Started Free