Understanding stacking rules for the HTML elements
March 21, 2022• ☕️ 4 min read
I thought I knew enough about how positioning and z-index works in HTML and CSS. But recently, I learned a new concept that completely took me by surprise. This article aims to share that knowledge with you and help you better understand how the z-index
works in HTML. Let’s get started.
Imagine you have two HTML div elements with exactly the same dimensions. The first element has position absolute
and a blue
background. The second one has a position relative
and a red
background as shown below.
<style>
div {
height: 200px;
width: 200px;
}
.first {
position: absolute;
background: blue;
}
.second {
position: relative;
background: red;
}
</style>
<div class="first">First element</div>
<div class="second">Second element</div>
What colour would you see on the page: blue
or red
?
If you think the answer is blue
because the absolute
positioned element will be taken out of the [normal page flow], and then the relative
positioned element should occupy that space underneath (as if the first element never existed), I am afraid you are wrong, and I was too 😛.
The correct answer is red
🤯.
Here’s the codepen example to demonstrate that:
Stacking without the z-index property
To understand this, we need to look at how elements are stacked in HTML when they don’t have any z-index property assigned.
As per Mozilla documentation, when z-index
property is not specified on the elements, they are stacked in the following order (from bottom to top)
- The background and borders of the root element
- Descendant non-positioned blocks, in order of appearance in the HTML
- Descendant positioned elements, in order of appearance in the HTML
Focusing on the third point above, we can conclude that the stack level of the positioned element will be exactly how their order of appearance is in the HTML. This is irrespective of their positioning
(absolute, relative, sticky, or fixed) type.
In our example code above, even though the first div has been taken out of the normal page flow, the relative element will be stacked above the first element as it appears second in the HTML order. And thus, you will see the red
colour instead of the blue 😍.
Changing the stack level with z-index
What we just learned is the default stacking behaviour of the elements without the z-index property. If you want to rearrange the stack order, you can do so by specifying z-index
property on a positioned element.
The z-index
can have any integer value that represents the position of an element along the z-axis. By default, the initial value of the z-index is auto
. It means that when no z-index
property is specified, elements are placed on layer 0
—the default rendering layer.
You can think of the z-index as a numerical value of the rendering layer.
Looking at our previous example above, if we specify z-index: 1
to the first div element, it will position the element on layer 1. The second element will be on layer 0. As a result you would see the blue
colour.
<style>
div {
height: 200px;
width: 200px;
}
.first {
position: absolute;
background: blue;
z-index: 1;
}
.second {
position: relative;
background: red;
}
</style>
<div class="first">First element</div>
<div class="second">Second element</div>
The stack order of the layers for the previous example would be like this:
Now, if we had the third non-positioned element (position: static) in the HTML example (appearing last in the HTML order), applying z-index value wouldn’t have affected it’s stack level. It will always be at the default rendering layer (layer 0).
The z-index only affects elements that have a position value other than static (the default)
But, if we had specified a negative z-index value for the second
positioned element, it would have stacked underneath the third
element. Let’s look at another example to clarify that.
<style>
body {
margin-top: 100px;
}
div {
opacity: 0.7;
border: 4px dotted;
margin-top: -40px;
text-align: center;
}
.first {
width: 200px;
height: 400px;
position: absolute;
background: blue;
z-index: 1;
}
.second {
width: 300px;
height: 300px;
position: relative;
background: red;
z-index: -1;
}
.third {
width: 400px;
height: 150px;
background: green;
z-index: 2;
}
...
</style>
<div class="first">First element</div>
<div class="second">Second element</div>
<div class="third">Third element</div>
The following picture should make it clear:
And here’s the Codepen demo to play with:
Final words
There’s one more important concept called stacking context which requires a separate article all together. The short explanation is that when a stacking context is formed, it creates a boundary around the descendant elements, and their z-index values can only influence their stacking order within the same context. The z-index value of elements inside one stacking context can’t influence the stacking order of other elements residing in a different stacking context.
The scope of the z-index is not global
Nonetheless, the stacking rules we just learned still applies as they are to the elements within the same stacking context. I highly recommend reading the following in-depth articles to understand how stacking context works.
Written by Amandeep Singh. Developer @ Avarni Sydney. Tech enthusiast and a pragmatic programmer.