Back in the early days of the web, websites were pretty flat, and not the good kind. However, since CSS2 we’ve had the ability to set the z-index property on elements. This literally added a whole new dimension to websites: The Z-axis! The z-index CSS property allows us to choose which elements appear behind or in front of others on the page. It sounds pretty straightforward, but there are some caveats if you’re not familiar with it. Let’s have a closer look:
Stacking without z-index
In the absence of a z-index property, HTML elements automatically stack in the following order:
- The root element
- Non-positioned elements (Elements with the default position property of static)
- Positioned elements (Elements with the position property set to absolute or relative)
When two elements fall on the same number in the list, they stack in the order that they are defined on the page.
Introducing the z-index property
When we introduce the z-index property into the mix, we gain more control over the stacking order of elements. It is however important to note that the z-index property only works on positioned elements.
When you apply the z-index to an element, it creates what is called a stacking context. See the below example:

The orange block has a higher z-index than the purple block, so why does it appear behind the purple block? The stacking context created by the z-index of the parent element creates limitations for its child elements. If you’re struggling to make an element appear on top, you might be tempted to use a large z-index value. However, if that doesn’t work, a parent elements’ stacking context might be to blame.
The z-index values of child elements in a stacking context do still affect each other. This allows you to change the order child elements appear in, but they cannot break out of their parent element’s stacking context.
Weird rules
This all might seem pretty straightforward, but there are some unexpected CSS properties that affect stacking contexts.
Have a look at the following example:
The z-indexes of the following blocks are 3, 2, and 1 respectively. Under normal circumstances, the first block would appear on top, followed by the second and third blocks.
However, here I’ve added a transform to the parent of the first span and opacity to the second. These two seemingly unrelated changes completely change the order in which the divs appear!
If you encounter a stacking issue but all your relevant elements are positioned, one of these rules could be to blame. For a full list of rules around stacking context, check out this link on the Mozilla developer docs.
In conclusion
Getting your elements to stack just right might not always be a piece of cake, there are some odd things to look out for. However, I hope that you’ve gained some insight into how it works by reading this post.
Have you had trouble with z-index before or is there another part of CSS that you struggle to grasp? Reach out to me on Twitter and let me know!