{"id":1150,"date":"2026-01-27T09:00:00","date_gmt":"2026-01-27T10:00:00","guid":{"rendered":"https:\/\/computercoursesonline.com\/?p=1150"},"modified":"2026-01-29T21:07:38","modified_gmt":"2026-01-29T21:07:38","slug":"unstacking-css-stacking-contexts","status":"publish","type":"post","link":"https:\/\/computercoursesonline.com\/index.php\/2026\/01\/27\/unstacking-css-stacking-contexts\/","title":{"rendered":"Unstacking CSS Stacking Contexts"},"content":{"rendered":"

Unstacking CSS Stacking Contexts<\/title><\/p>\n<article>\n<header>\n<h1>Unstacking CSS Stacking Contexts<\/h1>\n<address>Gabriel Shoyombo<\/address>\n<p> 2026-01-27T10:00:00+00:00<br \/>\n 2026-01-29T20:32:35+00:00<br \/>\n <\/header>\n<p>Have you ever set <code>z-index: 99999<\/code> on an element in your CSS, and it doesn\u2019t come out on top of other elements? A value that large should easily place that element visually on top of anything else, assuming all the different elements are set at either a lower value or not set at all.<\/p>\n<p>A webpage is usually represented in a two-dimensional space; however, by applying specific CSS properties, an imaginary z-axis plane is introduced to convey depth. This plane is perpendicular to the screen, and from it, the user perceives the order of elements, one on top of the other. The idea behind the imaginary z-axis, the user\u2019s perception of stacked elements, is that the CSS properties that create it combine to form what we call a <strong>stacking context<\/strong>.<\/p>\n<p>We\u2019re going to talk about how elements are \u201cstacked\u201d on a webpage, what controls the stacking order, and practical approaches to \u201cunstack\u201d elements when needed.<\/p>\n<h2 id=\"about-stacking-contexts\">About Stacking Contexts<\/h2>\n<p>Imagine your webpage as a desk. As you add HTML elements, you\u2019re laying pieces of paper, one after the other, on the desk. The last piece of paper placed is equivalent to the most recently added HTML element, and it sits on top of all the other papers placed before it. This is the normal document flow, even for nested elements. The desk itself represents the root stacking context, formed by the <code><html><\/code> element, which contains all other folders.<\/p>\n<p>Now, specific CSS properties come into play.<\/p>\n<p>Properties like <code>position<\/code> (with <code>z-index<\/code>), <code>opacity<\/code>, <code>transform<\/code>, and <code>contain<\/code>) act like a folder. This folder takes an element and all of its children, extracts them from the main stack, and groups them into a separate sub-stack, creating what we call a <strong>stacking context<\/strong>. For positioned elements, this happens when we declare a <code>z-index<\/code> value other than <code>auto<\/code>. For properties like <code>opacity<\/code>, <code>transform<\/code>, and <code>filter<\/code>, the stacking context is created automatically when specific values are applied.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/1-stacking-context-order.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"436\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Before (global stacking order) and after (stacking context order)\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/1-stacking-context-order.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n When the browser decides what goes on top, it stacks the folders first, not the individual papers inside them. This is \u201cThe Golden Rule\u201d of stacking contexts that many developers miss. (<a href=\"https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/1-stacking-context-order.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<blockquote><p>Try to understand this: Once a piece of paper (i.e., a child element) is inside a folder (i.e., the parent\u2019s stacking context), it can never exit that folder or be placed between papers in a different folder. Its <code>z-index<\/code> is now only relevant inside its own folder.<\/p><\/blockquote>\n<p>In the illustration below, Paper B is now within the stacking context of Folder B, and can only be ordered with other papers in the folder.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/2-stacking-contexts.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"436\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Before (global stacking order) and after (stacking context order)\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/2-stacking-contexts.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/2-stacking-contexts.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>Imagine, if you will, that you have two folders on your desk:<\/p>\n<pre><code class=\"language-html\"><div class=\"folder-a\">Folder A<\/div>\n<div class=\"folder-b\">Folder B<\/div>\n<\/code><\/pre>\n<pre><code class=\"language-css\">.folder-a { z-index: 1; }\n.folder-b { z-index: 2; }\n<\/code><\/pre>\n<p>Let\u2019s update the markup a bit. Inside Folder A is a special page, <code>z-index: 9999<\/code>. Inside Folder B is a plain page, <code>z-index: 5<\/code>.<\/p>\n<pre><code class=\"language-html\"><div class=\"folder-a\">\n <div class=\"special-page\">Special Page<\/div>\n<\/div>\n\n<div class=\"folder-b\">\n <div class=\"plain-page\">Plain Page<\/div>\n<\/div>\n<\/code><\/pre>\n<pre><code class=\"language-css\">.special-page { z-index: 9999; }\n.plain-page { z-index: 5; }\n<\/code><\/pre>\n<p>Which page is on top?<\/p>\n<p>It\u2019s the <code>.plain-page<\/code> in Folder B. The browser ignores the child papers and stacks the two folders first. It sees Folder B (<code>z-index: 2<\/code>) and places it on top of Folder A (<code>z-index: 1<\/code>) because we know that two is greater than one. Meanwhile, the <code>.special-page<\/code> set to <code>z-index: 9999<\/code> page is at the bottom of the stack even though its <code>z-index<\/code> is set to the highest possible value.<\/p>\n<p>Stacking contexts can also be nested (folders inside folders), creating a \u201cfamily tree.\u201d The same principle applies: a child can never escape its parents\u2019 folder.<\/p>\n<p>Now that you get how stacking contexts behave like folders that group and reorder layers, it\u2019s worth asking: why do certain properties — like <code>transform<\/code> and <code>opacity<\/code> — create new stacking contexts?<\/p>\n<p>Here\u2019s the thing: these properties don\u2019t create stacking contexts because of how they look; they do it because of how the browser works under the hood. When you apply <code>transform<\/code>, <code>opacity<\/code>, <code>filter<\/code>, or <code>perspective<\/code>, you\u2019re telling the browser, <em>\u201cHey, this element might move, rotate, or fade, so be ready!\u201d<\/em><\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/3-diagram-stacking-context.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"533\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Diagram illustrating the main document layout with an applied transform that creates a new stacking context, which in turn, runs on the GPU to handle the transformation. It indicates that a new stacking context is promoted for performance.\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/3-diagram-stacking-context.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/3-diagram-stacking-context.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>When you use these properties, the browser creates a new stacking context to manage rendering more efficiently. This allows the browser to handle animations, transforms, and visual effects independently, reducing the need to recalculate how these elements interact with the rest of the page. Think of it as the browser saying, <em>\u201cI\u2019ll handle this folder separately so I don\u2019t have to reshuffle the entire desk every time something inside it changes.\u201d<\/em><\/p>\n<p>But there\u2019s a side effect. Once the browser lifts an element into its own layer, it must \u201cflatten\u201d everything within it, creating a new stacking context. It\u2019s like taking a folder off the desk to handle it separately; everything inside that folder gets grouped, and the browser now treats it as a single unit when deciding what sits on top of what.<\/p>\n<p>So even though the <code>transform<\/code> and <code>opacity<\/code> properties might not appear to affect the way that elements stack visually, they do, and it\u2019s for performance optimisation. Several other CSS properties can also create stacking contexts for similar reasons. <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/CSS_positioned_layout\/Stacking_context#features_creating_stacking_contexts\">MDN provides a complete list<\/a> if you want to dig deeper. There are quite a few, which only illustrates how easy it is to inadvertently create a stacking context without knowing it.<\/p>\n<div data-audience=\"non-subscriber\" data-remove=\"true\" class=\"feature-panel-container\">\n<aside class=\"feature-panel\">\n<div class=\"feature-panel-left-col\">\n<div class=\"feature-panel-description\">\n<p>Meet <strong><a data-instant href=\"https:\/\/www.smashingconf.com\/online-workshops\/\">Smashing Workshops<\/a><\/strong> on <strong>front-end, design & UX<\/strong>, with practical takeaways, live sessions, <strong>video recordings<\/strong> and a friendly Q&A. With Brad Frost, St\u00e9ph Walter and <a href=\"https:\/\/smashingconf.com\/online-workshops\/workshops\">so many others<\/a>.<\/p>\n<p><a data-instant href=\"smashing-workshops\" class=\"btn btn--green btn--large\">Jump to the workshops \u21ac<\/a><\/div>\n<\/div>\n<div class=\"feature-panel-right-col\"><a data-instant href=\"smashing-workshops\" class=\"feature-panel-image-link\"><\/p>\n<div class=\"feature-panel-image\">\n<img loading=\"lazy\" class=\"feature-panel-image-img lazyload\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Feature Panel\" width=\"257\" height=\"355\" data-src=\"\/images\/smashing-cat\/cat-scubadiving-panel.svg\"><\/p>\n<\/div>\n<p><\/a>\n<\/div>\n<\/aside>\n<\/div>\n<h2 id=\"the-unstacking-problem\">The \u201cUnstacking\u201d Problem<\/h2>\n<p>Stacking issues can arise for many reasons, but some are more common than others. Modal components are a classic pattern because they require toggling the component to \u201copen\u201d on a top layer above all other elements, then removing it from the top layer when it is \u201cclosed.\u201d<\/p>\n<p>I\u2019m pretty confident that all of us have run into a situation where we open a modal and, for whatever reason, it doesn\u2019t appear. It\u2019s not that it didn\u2019t open properly, but that it is out of view in a lower layer of the stacking context.<\/p>\n<p>This leaves you to wonder \u201chow come?\u201d since you set:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-css\">.overlay {\n position: fixed; \/* creates the stacking context *\/\n z-index: 1; \/* puts the element on a layer above everything else *\/\n inset: 0; \n width: 100%; \n height: 100vh; \n overflow: hidden;\n background-color: #00000080;\n}\n<\/code><\/pre>\n<\/div>\n<p>This looks correct, but if the parent element containing the modal trigger is a child element within another parent element that\u2019s also set to <code>z-index: 1<\/code>, that technically places the modal in a sublayer obscured by the main folder. Let\u2019s look at that specific scenario and a couple of other common stacking-context pitfalls. I think you\u2019ll see not only how easy it is to inadvertently create stacking contexts, but also how to mismanage them. Also, how you return to a managed state depends on the situation.<\/p>\n<h3 id=\"scenario-1-the-trapped-modal\">Scenario 1: The Trapped Modal<\/h3>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"pvbddjd\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Scenario 1: The Trapped Modal (Problem) [forked]](https:\/\/codepen.io\/smashingmag\/pen\/pvbddjd) by <a href=\"https:\/\/codepen.io\/drprime01\">Shoyombo Gabriel Ayomide<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/pvbddjd\">Scenario 1: The Trapped Modal (Problem) [forked]<\/a> by <a href=\"https:\/\/codepen.io\/drprime01\">Shoyombo Gabriel Ayomide<\/a>.<\/figcaption><\/figure>\n<p>If you click the \u201cOpen Modal\u201d button in the header, you\u2019ll notice that the overlay and modal appear behind the main content. This is because the modal is a child of the header container, which has a lower stacking context order (<code>z-index: 1<\/code>) than the main container (<code>z-index<\/code> of <code>2<\/code>). Despite the modal overlay and the modal having <code>z-index<\/code> values of <code>9998<\/code> and <code>9999<\/code>, respectively, the main container with a <code>z-index: 2<\/code> still sits right above them.<\/p>\n<h3 id=\"scenario-2-the-submerged-dropdown\">Scenario 2: The Submerged Dropdown<\/h3>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"zxBPPvm\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Scenario 2: The Submerged Dropdown (Problem) [forked]](https:\/\/codepen.io\/smashingmag\/pen\/zxBPPvm) by <a href=\"https:\/\/codepen.io\/drprime01\">Shoyombo Gabriel Ayomide<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/zxBPPvm\">Scenario 2: The Submerged Dropdown (Problem) [forked]<\/a> by <a href=\"https:\/\/codepen.io\/drprime01\">Shoyombo Gabriel Ayomide<\/a>.<\/figcaption><\/figure>\n<p>Here, we have a similar issue with the first scenario. When you hover over the \u201cservices\u201d link, the dropdown shows, but behind the main container. I intentionally set the main container\u2019s <code>margin-top<\/code> to <code>20px<\/code> to make the dropdown visible enough for you to see it appear, but keep it just behind the main container. This is another popular issue front-end developers encounter, stemming from context stacking. While it is similar to the first scenario, there\u2019s another approach to resolving it, which will be explored soon.<\/p>\n<h3 id=\"scenario-3-the-clipped-tooltip\">Scenario 3: The Clipped Tooltip<\/h3>\n<p>Now, this is an interesting one. It\u2019s not about which element has the higher <code>z-index<\/code>. It\u2019s about <code>overflow: hidden<\/code> doing <a href=\"https:\/\/www.smashingmagazine.com\/2021\/04\/css-overflow-issues\/\">what it\u2019s designed to do<\/a>: preventing content from visually escaping its container, even when that content has <code>z-index: 1000<\/code>.<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"GgqOOoo\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Scenario 3: The Clipped Tooltip (Problem) [forked]](https:\/\/codepen.io\/smashingmag\/pen\/GgqOOoo) by <a href=\"https:\/\/codepen.io\/drprime01\">Shoyombo Gabriel Ayomide<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/GgqOOoo\">Scenario 3: The Clipped Tooltip (Problem) [forked]<\/a> by <a href=\"https:\/\/codepen.io\/drprime01\">Shoyombo Gabriel Ayomide<\/a>.<\/figcaption><\/figure>\n<p>Who would have thought <code>overflow: hidden<\/code> could stop a <code>z-index: 1000<\/code>? Well, it did stop it, as you can see in the Codepen above.<\/p>\n<p>I think developers trust <code>z-index<\/code> so much that they expect it to pull them out of any obscurity issue, but in reality, it doesn\u2019t work that way. Not that it isn\u2019t powerful, it\u2019s just that other factors determine its ability to push your element to the top.<\/p>\n<p>Before you slap <code>z-index<\/code> on that element, remember that while this might get you out of the current jam, it might also throw you into a greater one <a href=\"https:\/\/www.matuzo.at\/blog\/2025\/never-lose-a-z-index-battle-again\">that even <code>z-index: infinity<\/code> won\u2019t get you out of<\/a>.<\/p>\n<p>Let\u2019s try to understand the problem before attempting to fix it.<\/p>\n<div class=\"partners__lead-place\"><\/div>\n<h2 id=\"identifying-the-trapped-layer\">Identifying The Trapped Layer<\/h2>\n<p>When you encounter an issue such as those listed above, it is helpful to know that the element isn\u2019t possessed; instead, an ancestor has sinned, and the child is paying the debt. In non-spiritual English terms, the obscured element isn\u2019t the problem; an ancestor element has created a lower-level stacking context that has led the children to be below the children of a parent with a higher-level stacking context.<\/p>\n<p>A good way to track and find that parent is to descend into the browser\u2019s devtools to inspect the element and make your way up, checking each parent level to see which has a property or properties that trigger a stacking context, and find out its position in the order compared to sibling elements. Let\u2019s create a checklist to order our steps.<\/p>\n<h3 id=\"your-debugging-checklist\">Your Debugging Checklist<\/h3>\n<ol>\n<li><strong>Inspect the Problem Element.<\/strong><br \/>\nRight-click your hidden element (the modal, the dropdown menu, the tooltip) and click \u201cInspect.\u201d<\/li>\n<li><strong>Check its Styles.<\/strong><br \/>\nIn the \u201cStyles\u201d or \u201cComputed\u201d pane, verify that it has the expected high <code>z-index<\/code> (e.g., <code>z-index: 9999;<\/code>).<\/li>\n<li><strong>Climb the DOM Tree.<\/strong><br \/>\nIn the \u201cElements\u201d panel, look at the element\u2019s immediate parent. Click on it.<\/li>\n<li><strong>Investigate the Parent\u2019s Styles.<\/strong><br \/>\nLook at the parent\u2019s CSS in the \u201cStyles\u201d pane. You are now hunting for any property that creates a new stacking context. Look for any properties related to positioning, visual effects, and containment.<\/li>\n<li><strong>Repeat.<\/strong><br \/>\nIf the immediate parent is clean, click on its parent (the grandparent of your element). Repeat Step 4. Keep climbing the DOM tree, one parent at a time, until you find the culprit.<\/li>\n<\/ol>\n<p>Now, let\u2019s apply this checklist to our three scenarios.<\/p>\n<h3 id=\"problem-1-the-trapped-modal\">Problem 1: The Trapped Modal<\/h3>\n<ol>\n<li><strong>Inspect:<\/strong> We inspect the <code>.modal-content<\/code>.<\/li>\n<li><strong>Check Styles:<\/strong> We see <code>z-index: 9999<\/code>. That\u2019s not the problem.<\/li>\n<li><strong>Climb:<\/strong> We look at its parent, <code>.modal-container<\/code>. It has no trapping properties.<\/li>\n<li><strong>Climb Again:<\/strong> We look at its parent, the <strong><code>.header<\/code><\/strong>.<\/li>\n<li><strong>Investigate:<\/strong> We check the styles for <code>.header<\/code> and find the culprit: <code>position: absolute<\/code> and <code>z-index: 1<\/code>. This element is creating a stacking context. We\u2019ve seen our trap! The modal\u2019s <code>z-index: 9999<\/code> is \u201ctrapped\u201d inside a <code>z-index: 1<\/code> folder.<\/li>\n<\/ol>\n<h3 id=\"problem-2-the-submerged-dropdown\">Problem 2: The Submerged Dropdown<\/h3>\n<ol>\n<li><strong>Inspect:<\/strong> We inspect the <code>.dropdown-menu<\/code>.<\/li>\n<li><strong>Check Styles:<\/strong> We see <code>z-index: 100<\/code>.<\/li>\n<li><strong>Climb:<\/strong> We check its parent <code>li<\/code>, then its parent <code>ul<\/code>, then its parent <strong><code>.navbar<\/code><\/strong>.<\/li>\n<li>Investigate: We find <code>.navbar<\/code> has <code>position: relative<\/code> and <code>z-index: 1<\/code>. This creates Stacking Context A.<\/li>\n<li><strong>Analyse Siblings:<\/strong> This isn\u2019t the whole story. Why is it under the content? We now inspect the sibling of <code>.navbar<\/code>, which is <code>.content<\/code>. We find it has <code>position: relative<\/code> and <code>z-index: 2<\/code> (Stacking Context B). The browser is stacking the \u201cfolders\u201d: <code>.content<\/code> (2) on top of <code>.navbar<\/code> (1). We\u2019ve found the root cause.<\/li>\n<\/ol>\n<h3 id=\"problem-3-the-clipped-tooltip\">Problem 3: The Clipped Tooltip<\/h3>\n<ol>\n<li><strong>Inspect:<\/strong> We inspect the <code>.tooltip<\/code>.<\/li>\n<li><strong>Check Styles:<\/strong> We see <code>z-index: 1000<\/code>.<\/li>\n<li><strong>Climb:<\/strong> We check its parent, <code>.tooltip-trigger<\/code>. It\u2019s fine.<\/li>\n<li><strong>Climb Again:<\/strong> We check its parent, the <strong><code>.card-container<\/code><\/strong>.<\/li>\n<li><strong>Investigate:<\/strong> We scan its styles and find the culprit: <code>overflow: hidden<\/code>. This is a special type of trap. It clips any child that tries to render outside its boundaries, regardless of <code>z-index<\/code> values.<\/li>\n<\/ol>\n<h3 id=\"advanced-tooling\">Advanced Tooling<\/h3>\n<p>While climbing the DOM tree works, it can be slow. Here are tools that speed things up.<\/p>\n<h4 id=\"devtools-3d-view\">DevTools 3D View<\/h4>\n<p>Some browsers, such as Microsoft Edge (in the \u201cMore Tools\u201d menu) and Firefox (in the \u201cInspector\u201d tab), include a \u201c3D View\u201d or \u201cLayers\u201d panel. This tool is a lifesaver. It visually explodes the webpage into its different layers, showing you exactly how the stacking contexts are grouped.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/4-microsoft-edge-stacking-context.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"534\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Microsoft Edge 3D Stacking Context View\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/4-microsoft-edge-stacking-context.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Microsoft Edge 3D Stacking Context View. (<a href=\"https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/4-microsoft-edge-stacking-context.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>You can immediately see your modal trapped in a low-level layer and identify the parent.<\/p>\n<h4 id=\"browser-extensions\">Browser Extensions<\/h4>\n<p>Smart developers have built extensions to help. Tools like this <a href=\"https:\/\/chrome.google.com\/webstore\/detail\/z-context\/jigamimbjojkdgnlldajknogfgncplbhhttps:\/\/chrome.google.com\/webstore\/detail\/z-context\/jigamimbjojkdgnlldajknogfgncplbh\">\u201cCSS Stacking Context Inspector\u201d Chrome extension<\/a> add an extra <code>z-index<\/code> tab to your DevTools to show you information about elements that create a stacking context.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/5-browser-extensions.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"341\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"CSS Stacking Context Inspector Chrome extension\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/5-browser-extensions.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/5-browser-extensions.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<h4 id=\"ide-extensions\">IDE Extensions<\/h4>\n<p>You can even spot issues during development with an extension <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=mikerheault.vscode-better-css-stacking-contexts\">like this one for VS Code<\/a>, which highlights potential stacking context issues directly in your editor.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/6-ide-extensions.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"468\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Better CSS Stacking Contexts Extension\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/6-ide-extensions.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Better CSS Stacking Contexts Extension. (<a href=\"https:\/\/files.smashing.media\/articles\/unstacking-css-stacking-contexts\/6-ide-extensions.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<h2 id=\"unstacking-and-regaining-control\">Unstacking And Regaining Control<\/h2>\n<p>After we\u2019ve identified the root cause, the next step is to deal with it. There are several approaches you can take to tackle this problem, and I\u2019ll list them in order. You can choose anyone at any level, though; no one can complain or obstruct another.<\/p>\n<h3 id=\"change-the-html-structure\">Change The HTML Structure<\/h3>\n<p>This is considered the optimal fix. For you to run into a stacking context issue, you must have placed some elements in funny positions within your HTML. Restructuring the page will help you reshape the DOM and eliminate the stacking context problem. Find the problematic element and remove it from the trapping element in the HTML markup. For instance, we can solve the first scenario, \u201cThe Trapped Modal,\u201d by moving the <code>.modal-container<\/code> out of the header and placing it in the <code><body><\/code> element by itself.<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-html\"><header class=\"header\">\n <h2>Header<\/h2>\n <button id=\"open-modal\">Open Modal<\/button>\n <!-- Former position -->\n<\/header>\n<main class=\"content\">\n <h1>Main Content<\/h1>\n <p>This content has a z-index of 2 and will still not cover the modal.<\/p>\n<\/main>\n\n<!-- New position -->\n<div id=\"modal-container\" class=\"modal-container\">\n <div class=\"modal-overlay\"><\/div>\n <div class=\"modal-content\">\n <h3>Modal Title<\/h3>\n <p>Now, I'm not behind anything. I've gotten a better position as a result of DOM restructuring.<\/p>\n <button id=\"close-modal\">Close<\/button>\n <\/div>\n<\/div>\n<\/code><\/pre>\n<\/div>\n<p>When you click the \u201cOpen Modal\u201d button, the modal is positioned in front of everything else as it\u2019s supposed to be.<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"azZVVNP\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Scenario 1: The Trapped Modal (Solution) [forked]](https:\/\/codepen.io\/smashingmag\/pen\/azZVVNP) by <a href=\"https:\/\/codepen.io\/drprime01\">Shoyombo Gabriel Ayomide<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/azZVVNP\">Scenario 1: The Trapped Modal (Solution) [forked]<\/a> by <a href=\"https:\/\/codepen.io\/drprime01\">Shoyombo Gabriel Ayomide<\/a>.<\/figcaption><\/figure>\n<h3 id=\"adjust-the-parent-stacking-context-in-css\">Adjust The Parent Stacking Context In CSS<\/h3>\n<p>What if the element is one you can\u2019t move without breaking the layout? It\u2019s better to address the issue: <strong>the parent establishes the context.<\/strong> Find the CSS property (or properties) responsible for triggering the context and remove it. If it has a purpose and cannot be removed, give the parent a higher <code>z-index<\/code> value than its sibling elements to lift the entire container. With a higher <code>z-index<\/code> value, the parent container moves to the top, and its children appear closer to the user.<\/p>\n<p>Based on what we learned in \u201c<a href=\"-The-Submerged-Dropd\">The Submerged Dropdown<\/a>\u201d scenario, we can\u2019t move the dropdown out of the navbar; it wouldn\u2019t make sense. However, we can increase the <code>z-index<\/code> value of the <code>.navbar<\/code> container to be greater than the <code>.content<\/code> element\u2019s <code>z-index<\/code> value.<\/p>\n<pre><code class=\"language-css\">.navbar {\n background: #333;\n \/* z-index: 1; *\/\n z-index: 3;\n position: relative;\n}\n<\/code><\/pre>\n<p>With this change, the <code>.dropdown-menu<\/code> now appears in front of the content without any issue.<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"YPWEEWz\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Scenario 2: The Submerged Dropdown (Solution) [forked]](https:\/\/codepen.io\/smashingmag\/pen\/YPWEEWz) by <a href=\"https:\/\/codepen.io\/drprime01\">Shoyombo Gabriel Ayomide<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/YPWEEWz\">Scenario 2: The Submerged Dropdown (Solution) [forked]<\/a> by <a href=\"https:\/\/codepen.io\/drprime01\">Shoyombo Gabriel Ayomide<\/a>.<\/figcaption><\/figure>\n<h3 id=\"try-portals-if-using-a-framework\">Try Portals, If Using A Framework<\/h3>\n<p>In frameworks like <a href=\"https:\/\/react.dev\/reference\/react-dom\/createPortal\">React<\/a> or <a href=\"https:\/\/www.digitalocean.com\/community\/tutorials\/vuejs-portal-vue\">Vue<\/a>, a Portal is a feature that lets you render a component outside its normal parent hierarchy in the DOM. Portals are like a teleportation device for your components. They let you render a component\u2019s HTML anywhere in the document (typically right into <code>document.body<\/code>) while keeping it logically connected to its original parent for props, state, and events. This is perfect for escaping stacking context traps since the rendered output literally appears outside the problematic parent container.<\/p>\n<pre><code class=\"language-javascript\">ReactDOM.createPortal(\n <ToolTip \/>,\n document.body\n);\n<\/code><\/pre>\n<p>This ensures your dropdown content isn\u2019t hidden behind its parent, even if the parent has <code>overflow: hidden<\/code> or a lower <code>z-index<\/code>.<\/p>\n<p>In the \u201cThe Clipped Tooltip\u201d scenario we looked at earlier, I used a Portal to rescue the tooltip from the <code>overflow: hidden<\/code> clip by placing it in the document body and positioning it above the trigger within the container.<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"myEqqEe\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Scenario 3: The Clipped Tooltip (Solution) [forked]](https:\/\/codepen.io\/smashingmag\/pen\/myEqqEe) by <a href=\"https:\/\/codepen.io\/drprime01\">Shoyombo Gabriel Ayomide<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/myEqqEe\">Scenario 3: The Clipped Tooltip (Solution) [forked]<\/a> by <a href=\"https:\/\/codepen.io\/drprime01\">Shoyombo Gabriel Ayomide<\/a>.<\/figcaption><\/figure>\n<div class=\"partners__lead-place\"><\/div>\n<h2 id=\"introducing-stacking-context-without-side-effects\">Introducing Stacking Context Without Side Effects<\/h2>\n<p>All the approaches explained in the previous section are aimed at \u201cunstacking\u201d elements from problematic stacking contexts, but there are some situations where you\u2019ll actually need or want to create a stacking context.<\/p>\n<p>Creating a new stacking context is easy, but all approaches come with a side effect. That is, except for using <a href=\"https:\/\/css-tricks.com\/almanac\/properties\/i\/isolation\/\"><code>isolation: isolate<\/code><\/a>. When applied to an element, the stacking context of that element\u2019s children is determined relative to each child and within that context, rather than being influenced by elements outside of it. A classic example is assigning that element a negative value, such as <code>z-index: -1<\/code>.<\/p>\n<p>Imagine you have a <code>.card<\/code> component. You want to add a decorative shape that sits behind the <code>.card<\/code>\u2019s text, but on top of the card\u2019s background. Without a stacking context on the card, <code>z-index: -1<\/code> sends the shape to the bottom of the root stacking context (the whole page). This makes it disappear behind the <code>.card<\/code>\u2019s white background:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"QwEOOEM\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Negative z-index (problem) [forked]](https:\/\/codepen.io\/smashingmag\/pen\/QwEOOEM) by <a href=\"https:\/\/codepen.io\/drprime01\">Shoyombo Gabriel Ayomide<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/QwEOOEM\">Negative z-index (problem) [forked]<\/a> by <a href=\"https:\/\/codepen.io\/drprime01\">Shoyombo Gabriel Ayomide<\/a>.<\/figcaption><\/figure>\n<p>To solve this, we declare <code>isolation: isolate<\/code> on the parent <code>.card<\/code>:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"MYeOOeG\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Negative z-index (solution) [forked]](https:\/\/codepen.io\/smashingmag\/pen\/MYeOOeG) by <a href=\"https:\/\/codepen.io\/drprime01\">Shoyombo Gabriel Ayomide<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/MYeOOeG\">Negative z-index (solution) [forked]<\/a> by <a href=\"https:\/\/codepen.io\/drprime01\">Shoyombo Gabriel Ayomide<\/a>.<\/figcaption><\/figure>\n<p>Now, the <code>.card<\/code> element itself becomes a stacking context. When its child element — the decorative shape created on the <code>:before<\/code> pseudo-element — has <code>z-index: -1<\/code>, it goes to the very bottom of the parent\u2019s stacking context. It sits perfectly behind the text and on top of the card\u2019s background, as intended.<\/p>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>Remember: the next time your <code>z-index<\/code> seems out of control, it\u2019s a trapped stacking context.<\/p>\n<h3 id=\"references\">References<\/h3>\n<ul>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/CSS_positioned_layout\/Stacking_context\">Stacking context<\/a> (MDN)<\/li>\n<li><a href=\"https:\/\/web.dev\/learn\/css\/z-index\">Z-index and stacking contexts<\/a> (web.dev)<\/li>\n<li>\u201c<a href=\"https:\/\/www.freecodecamp.org\/news\/the-css-isolation-property\/\">How to Create a New Stacking Context with the Isolation Property in CSS<\/a>\u201d, Natalie Pina<\/li>\n<li>\u201c<a href=\"https:\/\/www.joshwcomeau.com\/css\/stacking-contexts\/\">What The Heck, z-index??<\/a>\u201d, Josh Comeau<\/li>\n<\/ul>\n<h3 id=\"further-reading-on-smashingmag\">Further Reading On SmashingMag<\/h3>\n<ul>\n<li>\u201c<a href=\"https:\/\/www.smashingmagazine.com\/2021\/02\/css-z-index-large-projects\/\">Managing CSS Z-Index In Large Projects<\/a>\u201d, Steven Frieson<\/li>\n<li>\u201c<a href=\"https:\/\/www.smashingmagazine.com\/2024\/09\/sticky-headers-full-height-elements-tricky-combination\/\">Sticky Headers And Full-Height Elements: A Tricky Combination<\/a>\u201d, Philip Braunen<\/li>\n<li>\u201c<a href=\"https:\/\/www.smashingmagazine.com\/2019\/04\/z-index-component-based-web-application\/\">Managing Z-Index In A Component-Based Web Application<\/a>\u201d, Pavel Pomerantsev<\/li>\n<li>\u201c<a href=\"https:\/\/www.smashingmagazine.com\/2009\/09\/the-z-index-css-property-a-comprehensive-look\/\">The Z-Index CSS Property: A Comprehensive Look<\/a>\u201d, Louis Lazaris<\/li>\n<\/ul>\n<div class=\"signature\">\n <img src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Smashing Editorial\" width=\"35\" height=\"46\" loading=\"lazy\" class=\"lazyload\" data-src=\"https:\/\/www.smashingmagazine.com\/images\/logo\/logo--red.png\"><br \/>\n <span>(gg, yk)<\/span>\n<\/div>\n<\/article>\n","protected":false},"excerpt":{"rendered":"<p>Unstacking CSS Stacking Contexts Unstacking CSS Stacking Contexts Gabriel Shoyombo 2026-01-27T10:00:00+00:00 2026-01-29T20:32:35+00:00 Have you ever set z-index: 99999 on an element in your CSS, and it doesn\u2019t come out on top of other elements? A value that large should easily place that element visually on top of anything else, assuming all the different elements are…<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[11],"tags":[],"_links":{"self":[{"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/posts\/1150"}],"collection":[{"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/comments?post=1150"}],"version-history":[{"count":1,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/posts\/1150\/revisions"}],"predecessor-version":[{"id":1151,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/posts\/1150\/revisions\/1151"}],"wp:attachment":[{"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/media?parent=1150"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/categories?post=1150"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/tags?post=1150"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}