4 Reasons Why z-index Isn't Working (And How to Fix It) (2024)

If you've ever worked with z-index before, you know it can be a real trickster. In theory, it seems simple enough - the higher the number, the more on top the element should be in the stacking order.

But in reality, there are several gotchas and guidelines you need to follow for z-index to behave properly...

And let's be honest, a lot of those rules aren't very intuitive at all.

Z-index has tripped up pretty much every developer at some point, even the experienced ones among us.

We've all been there - you assign a nice high z-index value to an element, fully expecting it to appear on top, only to be utterly confused when it stubbornly refuses to show up over the other elements on the page.

No obvious reason why, just...stuck behind everything else.

In this post, I'll be going over the four main culprits behind misbehaving z-index values, and showing you how to fix each issue with real code examples.

The four troublemakers are:

  1. Elements in the same stacking context displaying in an unexpected order

  2. Elements needing positioned values for z-index to actually do anything

  3. Certain CSS properties creating new (and often surprise) stacking contexts

  4. An element's z-index being limited by its parent's value

By understanding what's really going on under the hood in each of these situations, you'll be able to finally wrangle z-index into submission.

Let's dive in.

Reason 1: Elements in the same stacking context displaying in an unexpected order

Alright, let's tackle the first reason z-index seems to fail us - elements in the same stacking context displaying in an order we didn't intend.

What does that even mean?

4 Reasons Why z-index Isn't Working (And How to Fix It) (1)

If we look at the image above, we have a basic layout with three elements: an image of a dog at the top, a blue box with text in the middle, and another dog image at the bottom.

Now, our goal is for the blue text box to appear on top of both dog images.

Here's the exact code that brought about that image above:

<section class="content"> <div class="dog-top"></div> <div class="content-block">Dogs are wonderful</div> <div class="dog-bottom"></div></section>

In the html code above, we have a section with three child elements:

  1. A .dog-top div

  2. A .content-block div containing text

  3. A .dog-bottom div

The CSS:

body { background-color: #f4f4f4; padding: 20px;}.content { position: relative;} .dog-top, .dog-bottom { width: 120px; height: 120px; background-image: url(../dog.jpg); background-size: cover; background-position: center center; }.dog-top { margin-bottom: -60px;}.content-block { background-color: blue; text-align: center; color: #fff; padding: 50px; z-index: 12; /*trying to move it up*/}.dog-bottom { float: right; margin-top: -60px;}

we can see that even though we have set a z-index of 12 on .content-block, it is still appearing behind the .dog-bottom div.

This is because when elements are siblings in the same stacking context (meaning they are at the same level without having any positioning applied), their stacking order is determined strictly by their source order in the HTML.

Since the .dog-bottom div comes after the .content-block in the HTML, it will be displayed on top of the .content-block, ignoring the z-index value.

To fix this issue, we need to create a new stacking context for the .content-block element.

We can do this by setting position: relative on it:

.content-block { background-color: blue; text-align: center; padding: 50px; z-index: 12; position: relative; /* Creates a new stacking context */}

The result:

4 Reasons Why z-index Isn't Working (And How to Fix It) (2)

Our goal has been achieved!

By adding position: relative, the .content-block element now has its own stacking context separate from its siblings.

This allows its z-index of 12 to take effect, causing it to display on top of the .dog-top and .dog-bottom divs.

The key takeaway is: When sibling elements share the same stacking context (none are positioned), their ordering is based purely on their source order in the HTML, regardless of z-index values.

Creating a new stacking context by positioning an element allows you to escape source order stacking and utilize z-index values as expected.

Reason 2: Elements Need Positioned Values for z-index to Work

Okay, we solved the first issue by creating a new stacking context with positioning. But what if you DO apply z-index values and things still don't stack up properly?

Here's the deal: z-index only works on positioned elements. So if you set z-index on an element with position: static (the default), it won't do anything at all. The z-index is entirely ignored for non-positioned elements.

Let's look at another code example to illustrate this point...

<div class="container"> <div class="box red"></div> <div class="box green"></div> <div class="box blue"></div></div>
.container { position: relative;}.box { width: 200px; height: 200px; position: static; /* Default static positioning */}.red { background-color: red; z-index: 3; /* z-index ignored on static elements */}.green { background-color: green; z-index: 2; margin-top: -100px; margin-left: 100px;}.blue { background-color: blue; z-index: 1; margin-top: -100px; margin-left: 200px;}

In this initial code, even though the .red box has the highest z-index of 3, it still appears behind the .green and .blue boxes.

This is because the z-index values are being ignored since all the boxes have position: static (the default).

4 Reasons Why z-index Isn't Working (And How to Fix It) (3)

To fix it, we set a positioned value on the .red box:

.red { background-color: red; z-index: 3; position: relative; /* z-index now works! */}

Result:

4 Reasons Why z-index Isn't Working (And How to Fix It) (4)

As you can see, once we added a positioned value like position: relative to the element, then the z-index kicked in and allowed us to control the stacking order accurately.

So in summary: if you're fighting with z-index and nothing seems to be working, double check that you've set positioning (relative, absolute, etc) on the elements, or z-index won't even be a factor.

With that sticky wicket out of the way, we can progress to the next z-index issue that loves to cause headaches...

Reason 3: Some CSS Properties Create a New Stacking Context

Just when you thought you had a handle on z-index, here's another curveball - certain CSS properties will automatically create a new stacking context for that element.

What does that mean?

Well, it's like giving that element a fresh slate and its own mini z-index universe, separate from its siblings.

The main properties that trigger a new stacking context are:

  1. opacity less than 1

  2. transform (any value except none)

  3. filter

  4. mix-blend-mode

  5. isolation

Let's look at an example where this bites us.

<!DOCTYPE html><html><head> <title>Stacking Context Example</title> <style> .box { width: 200px; height: 200px; font-size: 24px; text-align: center; line-height: 200px; } .green { background-color: green; margin-top: 200px; z-index: 1; opacity: 0.9; /* Creates a new stacking context */ } .blue { background-color: blue; margin-top: -250px; margin-left: 150px; color: white; z-index: 4; } </style></head><body> <div class="container"> <div class="box green">Green Box</div> <div class="box blue">Blue Box</div> </div></body></html>

In this example, we have two colored boxes: a green box with a z-index of 1 and an opacity of 0.9 (which creates a new stacking context), and a blue box with a z-index of 4.

According to the z-index values alone, the expected order should be:

  1. Green Box (z-index: 1) lower

  2. Blue Box (z-index: 4) upper

However, because we applied an opacity: 0.9 to the green box, it creates a new stacking context, overriding the z-index values we assigned.

As a result, the order becomes:

4 Reasons Why z-index Isn't Working (And How to Fix It) (5)

  1. Blue Box (z-index: 4)

  2. Green Box (z-index: 1, but on top due to the new stacking context)

You can see that the green box appears on top of the blue box, even though the blue box has a higher z-index value of 4.

The solution is to keep things simple by removing the opacity property in the green box...

but if you must, then add position:relative and a higher z-index if necessary:

.blue { background-color: blue; margin-top: -250px; margin-left: 160px; color: white; position: relative; z-index: 5; /* if you must */}
  1. Green Box (z-index: 1, new stacking context due to opacity: 0.9)

  2. Blue Box (z-index: 5)

4 Reasons Why z-index Isn't Working (And How to Fix It) (6)

By understanding which properties cause new stacking contexts, we can properly plan our z-index values to account for them. It requires being extra explicit, but that's the name of the game with z-index!

Reason 4: An Element's z-index is Limited by Its Parent

Even if you've carefully set z-index values while avoiding stacking context issues, there's one more frustrating scenario that can throw it off - being limited by a parent element's z-index value.

Here's how it works: A child element can never be higher than the stacking context of its parent.

So, if a parent has a lower z-index value, its children will be bound by that stacking level no matter what.

Let's look at an example:

<div class="parent"> <div class="child"></div></div><div class="overlay"></div>
.parent { position: relative; z-index: 1;}.child { position: absolute; z-index: 100; width: 200px; height: 200px; background-color: blue;}.overlay { position: fixed; z-index: 10; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5);}

In this example, we have a parent container with a z-index of 1, a child element with a z-index of 100, and an overlay with a z-index of 10.

You might expect the child element to appear on top of the overlay because its z-index is higher.

However, due to the stacking context created by the parent's z-index of 1, the child element is limited to that stacking level, even though its individual z-index is set to 100.

This is the outcome of the code above:

4 Reasons Why z-index Isn't Working (And How to Fix It) (7)

To solve this issue, you can either:

  1. Move the child element outside of the limiting parent container, or

  2. Remove the z-index value from the parent container, if possible.

Here's an example of the first solution:

<div class="parent"> <!-- Child element moved outside --></div><div class="child"></div><div class="overlay"></div>

By moving the child element outside of the parent container, it is no longer limited by the parent's stacking context, and its z-index of 100 can take effect, allowing it to appear on top of the overlay.

Remember, an element's z-index value is relative to its stacking context, which is determined by the z-index values of its parent elements. Keeping this in mind can help you troubleshoot and resolve issues where elements aren't appearing in the expected stacking order.

And there you have it! The 4 main reasons why z-index doesn't behave as expected, demystified with real examples. While z-index seems simple on the surface, these nuances around stacking contexts make it a force to be reckoned with in CSS. But armed with this knowledge, you can finally tame that z-index beast!

That covers the 4 main reasons why z-index may not work as expected, along with code examples and solutions for each issue.

Conclusion

Working with z-index can be incredibly frustrating, but also extremely important for controlling layout and overlay elements on a web page.

While this CSS property seems straightforward, the nuances around stacking contexts make it deceptively complex.

To summarize, the 4 key reasons why z-index may not behave as you'd expect are:

  1. Elements in the same stacking context order by source

  2. Positioned values are required for z-index to work

  3. Certain properties create a new stacking context

  4. A child's z-index is limited by its parent's value

By understanding and accounting for these factors, you can finally wrestle z-index into submission and achieve the proper stacking order. Just be sure to follow best practices:

- Always use positioned values (relative, absolute, etc) along with z-index

- Be explicit with z-index values, using higher increments to future-proof

- Watch out for stacking context creating properties

- Check for limiting parent z-index values

- Inspect elements in browser devtools to debug

With some patience and these strategies in your toolbelt, you'll be a z-index wrangling master in no time! No more hair-pulling frustration from those quirky stacking issues.

What's your biggest z-index headache or "ah-ha!" moment? Let me know in the comments below. And if you found this guide helpful, share it with others who could use some stacking order sanity!

4 Reasons Why z-index Isn't Working (And How to Fix It) (2024)
Top Articles
Latest Posts
Recommended Articles
Article information

Author: Manual Maggio

Last Updated:

Views: 5683

Rating: 4.9 / 5 (69 voted)

Reviews: 84% of readers found this page helpful

Author information

Name: Manual Maggio

Birthday: 1998-01-20

Address: 359 Kelvin Stream, Lake Eldonview, MT 33517-1242

Phone: +577037762465

Job: Product Hospitality Supervisor

Hobby: Gardening, Web surfing, Video gaming, Amateur radio, Flag Football, Reading, Table tennis

Introduction: My name is Manual Maggio, I am a thankful, tender, adventurous, delightful, fantastic, proud, graceful person who loves writing and wants to share my knowledge and understanding with you.