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 ofz-index: auto
In order for
z-index
to work, we must define aposition
value other thatstatic
z-index
will work with flex and grid without defining aposition
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>
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)