DEV Community

Cover image for Ending z-index confusion, once and for all.
Marwan Ahmed
Marwan Ahmed

Posted on

Ending z-index confusion, once and for all.

Yes, we've all been there... writing z-index: 99999; and almost smashing the screen because one element isn't being put on top of another.

Before you start reading, if your goal is to skim through the article in order find a quick fix for your bug, I'm sorry to disappoint you (I'm not actually), you won't find what you're looking for.

The goal of this article is to make you super confident the next time you're adding random numbers in a z-index... that your solution won't work!


First, let's mention two basic but very important rules when it comes to stacking element on top of each other:

  • If an element does not have a defined z-index, it will have a value of z-index: auto

  • In order for z-index to work, we must define a position value other that static

  • z-index will work with flex and grid without defining a position

  • Elements further down the document sit on top of elements that appear before them.

In order to understand the problems with z-index, it's crucial that we grasp a very important concept called Stacking Contexts.


Stacking Contexts

Stacking contexts is the reason why your 99999 doesn't work. So, what in the world is that thing that is causing developers pain?

Let's make this simple using a dumb analogy. Let's assume that we're comparing the ages of parents and children. We have 2 fathers and each father has 2 sons. Ahmed has Omar (yes, it's my brother's name) and Marwan. Mark has John and Jack.

The rules are that we cannot compare the age of a child to the age of a father, and we cannot compare the age of a child to the age of a child of another father. Meaning we can only compare either the ages of the two fathers (Ahmed and Mark), or the ages of two brothers.

When a father has his first child, he starts creating a family (stacking context). It's logically impossible for one of his children to be older than him. His children cannot outgrow him no matter how tall they are or how much weight they put on (z-index: 99999;).

<div class="position-relative z-index-2" id="Ahmed">
   <p class="position-relative z-index-10" id="Marwan"></p>
   <p class="position-relative z-index-1000" id="Omar"></p>
</div>

<div class="position-relative z-index-1" id="Mark">
   <p class="position-relative z-index-10" id="John"></p>
   <p class="position-relative z-index-1000" id="Jack"></p>
</div>
Enter fullscreen mode Exit fullscreen mode

In this example, the div with id Ahmed creates a stacking context when it has position: relative and z-index: 2, so it starts having its own family.

So, the child with id Omar, will never grow above its parent, although he has a much higher z-index.

In the same family, we can compare both brothers, so Omar is above Marwan.

Now, what if we want to compare Ahmed with Mark? Since they both created their own families (stacking contexts), they're both fathers, so we can compare them. In this case, Ahmed will be above Mark, since Ahmed has a higher z-index.

How about comparing Mark with Omar? As mentioned above, we cannot compare fathers to children of other fathers. In this case, we will have to compare Mark to the Omar's father Ahmed.

This is the gist of stacking contexts and why sometimes higher z-index doesn't make any difference.

There are scenarios where children can be above their parents. This is when the parent doesn't have a position other than static.

In this case, the parent did not create a new stacking context, so the child is being compared in the root stacking context, even if the parent has a z-index.

Referring to our analogy, it's as if the child Omar has grown to be a father and is now being compared to other fathers.


Solutions

Knowing the problem is half the solution. Since the problem is now clear, you might think "Well, if the problem is that the child is trapped inside it's parent's stacking context, maybe the solution is to find a way to move the child outside". You'd be exactly right, and that's what Vue and React teams have done when they created Portal and Teleport.

Portal and Teleport are used to teleport a certain element (dropdown, modals, popovers) to the body, in order to free it from it's parent's stacking context.

Other solutions might include restructuring your html, playing with elements' position property, you get the idea.


Summary

Here's a flowchart that summarizes the above, and helps you grasp the concept clearly. (I asked ChatGPT to do it but it failed miserably so I did it. The disappointments of AI...)

Hopefully that's the end of random 9's thrown around in your code.

Maybe you can even show-off to your team and explain to them what you've understood 😉.

If you have any questions or any feedback, drop them below. I'd love to hear from you.

Top comments (0)