[5 FIXES] for CSS z-index not working - Updated for 2023

A common issue when design web layouts is making sure one element appears in front or behind another element. One way to stack elements is to use the z-index CSS property. We will go over some reasons for z-index is not working as expected and troubleshoot and review solutions that we can apply to.

Apr 19, 2022 | Read time 14 minutes | Updated on Sep 14, 2023

🔔 Table of contents

Introduction

A common issue when design web layouts is making sure one element appears in front or behind another element. For example, when creating a fixed header or modal - we want that to always appear and on top of other elements.

One way to stack elements is to use the z-index CSS property. Sometimes we want an element to appear in front of everything, but it does not work (for example setting z-index:99999 !important doesnt work :O)

In this post I will go over some reasons for z-index is not working as expected and troubleshoot and review solutions that we can apply to.

What is z-index?

With most scenarios, layering out HTML elements is within two dimentions - you can place images, text, videos on the page and the elements do not have to touch each over. They will flow with the order that was added to the DOM.

When you need to place one element over another or behind a different element, we can use the z-index property. This just means that we have now introduced a stacking context - enabling elements to be stacked on top of each other.

Fix 1 - check if stacking enabled!

When we are not seeing the elements being stacked correctly, we need to check if stacking is enabled

The stacking context

The stacking context is just a way of saying how the elements will be stacked along the z-axis of the page. So elements that are stacked will appear closer or farther away from the user. We can trigger this using the z-index CSS property.

A high z-index such as: 9999, the element will appear on the very top, and a z-index of negative such as -1, the element will be at the bottom.

More information here:https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context

! For example, consider the following HTML and CSS

<div class="contentA"></div>

<div class="contentB"></div>
.contentA{
  width: 80px;
  height: 80px;
  background: red;
  z-index: 2;
}

.contentB{
  width: 100px;
  height: 100px;
  background: blue;
  z-index:1;
}

From the above - we have specified z-index properties for .contentA and .contentB elements, but we cant see them stacking. This issue is because we have not enabled the stacking context! Setting the z-index alone does not trigger it, we will need to use the position property:

The .contentA element will need to have a position value absolute, relative, sticky or fixed. Additionally z-index value other than auto.

Now if we add position: absolute to .contentA, we can see it will be stacked on top on .contentB

.contentA{
  width: 80px;
  height: 80px;
  background: red;
  position:absolute; /* added this to enable stacking context */
  z-index: 2;
}

.contentB{
  width: 100px;
  height: 100px;
  background: blue;
  z-index:1;
}

👉 Conditions to enable stacking (in addition to adding a z-index):

  • CSS property of the element to be position value absolute or relative and z-index value other than auto.
  • CSS property of the element with position value fixed or sticky (sticky for all mobile browsers, but not older desktop).
  • CSS property of the element that is a child of a flex container, with z-index value other than auto.
  • CSS property of the element that is a child of a grid container, with z-index value other than auto.
  • CSS property of the element with a opacity value less than 1.
  • CSS property of the element with a mix-blend-mode value other than normal.
  • CSS property of the element with any of the following properties with value other than none:
    • transform
    • filter
    • backdrop-filter
    • perspective
    • clip-path
    • mask / mask-image / mask-border
  • CSS property of the element with a isolation value isolate.
  • CSS property of the element with a will-change value specifying any property that would create a stacking context on non-initial value.
  • CSS property of the element with a contain value of layout, or paint.

Fix 2 - check parent element’s z-index

Another thing to consider/ troubleshoot when having z-index issues is the parent element’s z-index. The stacking order of a child element will be based on the parent’s z-index. It can not go higher than that. For example, consider the following HTML, we added a .contentC as a child element to .contentB.

Now, if we want .contentC to appear higher than .contentA, it would not be possible! This is because .contentC belongs to .contentB (z-index:1) - which has a lower z-index than .contentA (z-index:2)

<div class="contentA">
</div>

<div class="contentB">
  
  <div class="contentC"> <!-- This element cannot go higher than .contentA -->
  </div>
</div>
.contentA{
  width: 80px;
  height: 80px;
  background: red;
  position: absolute;
  z-index: 2;
}

.contentB{
  width: 100px;
  height: 100px;
  background: blue;
  position:absolute;
  z-index:1;
}

.contentC{
  width: 40px;
  height: 40px;
  background: yellow;
  z-index:3;
  position:absolute;
  bottom:0;
  right:0
}

As we can see - .contentC (yellow) will appear lower than .contentA!

👉 How to fix parent z-index

Theres a few ways to fix this issue. Some of them are as follows:

  1. Make .contentB position:static - this is the default value - the element will be position based on the follow of the document.
.contentA{
  width: 80px;
  height: 80px;
  background: red;
  position: absolute;
  z-index: 2;
}

.contentB{
  width: 100px;
  height: 100px;
  background: blue; 
  position:static; /* added this remove from the stacking context */
  z-index:1;
}

.contentC{
  width: 40px;
  height: 40px;
  background: yellow;
  z-index:3;
  position:absolute;
  top:0;
  left:0
}
  1. Another way to fix this is to move the child element outside of the parent. In this case we move .contentC to the same level as .contentB and .contentA:
<div class="contentA">
</div>

<div class="contentB">
  

</div>
<div class="contentC"> <!-- moved outside to be some level as other elements -->
</div>

Then we can set the z-index to be z-index:3 and it will appear on top of the other elements. This is a common pattern with UI elements such as fixed navigation, modals or loading elements.

.contentA{
  width: 80px;
  height: 80px;
  background: red;
  position: absolute;
  z-index: 2;
}

.contentB{
  width: 100px;
  height: 100px;
  background: blue;
  position:absolute;
  z-index:1;
}

.contentC{
  width: 40px;
  height: 40px;
  background: yellow;
  z-index:3;
  position:absolute;
  bottom:0;
  right:0
}

Fix 3 - Check z-index value range

One thing to consider is the actualy z-index value range. There are maximums and minimums of the z-index based on browsers. Generally with modern browsers, the max value for z-index is a 32 bit integer 2147483647 and minimum value is -2147483647.

If you specify any values outside of this range, the browser doesnt crash, but prone to integer overflow issues.

More information here:

https://www.w3.org/TR/CSS22/visuren.html#z-index

Browser Maximum
Chrome >= 29 2,147,483,647
Opera >= 9 2,147,483,647
IE >= 6 2,147,483,647
Safari >= 4 2,147,483,647
Safari = 3 16,777,271
Firefox >= 4 2,147,483,647
Firefox = 3 2,147,483,647
Firefox = 2 2,147,483,647

Additionally keep in mind that having a z-index:auto will not trigger the stacking context! Elements with z-index:auto will be ordered by appearance in the HTML.

Fix 4 - browser support & bugs

Browser support for z-index is quite good - with full support across modern browsers such as Chrome, Firefox, Opera, Safari and even IE (internet explorer).

We can see that it is supported with the latest versions:

https://caniuse.com/?search=z-index

Fix 5 - check the stacking order

The stacking order is formed from the following rules:

  1. The stacking context’s root element
  2. Positioned elements (and their children) with negative z-index values
  3. Non-positioned elements (ordered by appearance in the HTML)
  4. Positioned elements (and their children) with a z-index value of auto (ordered by appearance in the HTML)
  5. Positioned elements (and their children) with positive z-index values

Negative z-index elements are ordered first within the stacking context.

Lets say we have the following example with HTML and CSS:

<div><!-- 1 -->
  <span class="red"></span> <!-- 6 -->
</div>
<div><!-- 2 -->
  <span class="green"><span> <!-- 4 -->
</div>
<div><!-- 3 -->
  <span class="blue"></span> <!-- 5 -->
</div>
.red {
  z-index: 1;
  top: 20px;
  left: 20px;
  background: red;
}

All boxes will be positioned and red will be the only one with z-index:1 applied. The other boxes will take the default value of z-index:auto. So in this case, according to the stacking order rules, we can see that the red box will be the last rendered since it has the highest z-index.

The stacking order number is placed next to each div - the red box got stacking order number of 6

Now if we add the following CSS:

div:first {
    opacity:0.99;
}

The red box will appear at the back, because now opacity other than 1 will trigger another stacking context. Now the order of stacking is:

<div><!-- 1 -->
  <span class="red"></span> <!-- 1.1 -->
</div>
<div><!-- 2 -->
  <span class="green"><span> <!-- 4 -->
</div>
<div><!-- 3 -->
  <span class="blue"></span> <!-- 5 -->
</div>

The browser will stack the first div first and then stack the red box. This will make the red box appear behind the other boxes:

Further Tips

There are a variety of tools to check the z-index. If you are using Microsoft Edge we can use the 3D view (https://docs.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/3d-view/):

image of how to view z index in 3d in the edge browser

Another awesome tool that I have recently tried and seems to work pretty well is CSS Stacking Context Inspector -

The extension is for Chrome and Firefox add a new panel that will show stacking contexts in a tree view, and will also append a new sidebar to the elements panel with some useful information about the selected element.

Image of using Google Chrome DevTools to view stacking context

https://chrome.google.com/webstore/detail/css-stacking-context-insp/apjeljpachdcjkgnamgppgfkmddadcki

https://addons.mozilla.org/en-US/firefox/addon/css-stacking-context-inspector/

Conclusion

In this article we went through some common issues with the z-index not working and solutions on how to fix them. When troubleshooting, we need to consider if the stacking context is enabled.

The stacking context is just a way to display elements on the z-axis - closer or futher away from the user.

Most commonly the stacking context is enabled when we specify z-index:<integer> and not z-index:auto. Additionally, the element have to be positioned, so any position property such as position:relative, position:absolute, position:sticky, and position:fixed. The default value for position: position:static will just order the elements by appearance and not enable the stacking context.

We also need to check the parent’s z-index. The child element’s z-index is limited by the parent.

✅ A quick checklist to troubleshoot z-index issues:

  1. Check z-index value is not auto, and the element position is relative, absolute, static or fixed
  2. Check properties that enable stacking context is used, such as opacity, mix-blend-mode, will-change
  3. Verify that the parent element is not restricting the child element’s z-index. The child elements max stacking order is limited to the parent’s value
  4. Make sure that z-index value is within the 32 bit integer range with max of 2,147,483,647 and min of negative 2,147,483,647. For Safari 3, the max is 16,777,271
  5. Check the stacking order of each element - properties such as opacity will trigger another stacking context.
  6. Use tools such as 3D View if you have Microsoft Edge and for Chrome, Firefox - use CSS Stacking Context Inspector

👋 About the Author

G'day! I am Huy a software engineer based in Australia. I have been creating design-centered software for the last 10 years both professionally and as a passion.

My aim to share what I have learnt with you! (and to help me remember 😅)

Follow along on Twitter , GitHub and YouTube