Are you wrecking your brain trying to figure out the stacking order of HTML elements? Let us lend you a helping hand and do the heavy lifting for you.
First things first, here’s what you need to know about the z-index: The z-index CSS property sets the z-order. That’s why developers use it to determine the order in which elements are positioned within the stacking order.
Usually, 2 types of errors occur. The first one is because the z-index only works when an element is a) a positioned element, b) a flex item or c) a grid item.
- Positioned element refers to an element whose position property is other than <static>.
- Flex items are elements whose parent element’s display property is <flex> or <inline-flex>.
- As for grid items, the parent element’s display property is <grid> or <inline-grid>.
If you’ve used z-index and for some reason, it didn’t work out, it might be that you used it on the wrong elements. So, you can first try one of the above-mentioned tricks and see if it solves your problem.
The second most common mistake is that developers assume that they only need the z-index to determine the stacking order of elements. That’s how they end up leaving other rules that are necessary for revealing the exact position of elements out of the equation.
But there’s no need to give up hope and smash your computer against the wall just yet. We’ll walk you through all the necessary steps.
- First, we’ll take a look at the layered presentation of HTML elements.
- Next, we’ll define what a stacking context is.
- Then we’ll show you how to identify elements that generate stacking contexts.
- Finally, we’ll share the necessary rules to figure out the elements’ order within a stacking context.
We promise we have all the answers you need!
In CSS, you have to imagine every HTML element in three dimensions. As the image shows, each element can either be positioned horizontally, vertically or along the z-axis. While the first two positions are a no-brainer, let’s take a look at why the z-axis position is so important.
We’ll use 10Web’s landing page for the AI website builder as an example.
On the bottom right of this page, you see two call to action (CTA) buttons. One tells people to “Hurry up” and get the lifetime deal, while the other encourages users to “Ask a question.” If you take a close look, you’ll notice that those CTAs are hovering over the website. Even if you scroll down they’ll stay on the front covering whatever is behind them.
What does that tell us? Exactly, that the CTAs and the web page content overlap and that the CTA buttons are on the front side of the page. Basically, that’s why the z-axis position is so important because it shows you how elements are stacked.
What is a stacking context?
You can basically imagine a stacking context as a bunch of elements that have a common parent. Here’s the thing though: Stacking contexts can contain other stacking contexts generated by their child elements. Every element belongs to one stacking context and that stacking context is the one nearest to the element. Keep in mind that within a stacking context the groups of elements move together along the z-axis.
Basically, you have one HTML element as the root element of every stacking context. Whenever such an element generates a stacking context, all of this element’s child elements get their specific stack level. The stack level refers to the position of an element along the z-axis relative to other stack levels within the same stacking context.
What’s important here is that elements are separated by stacking contexts. Put differently, the elements of one stacking context can’t come between the elements of another stacking context. So the position of an element is always relative to its own stacking context rather than to other stacking contexts.
Here’s what we can derive from all this:
- If an element belongs to a stacking context that’s at the bottom of the stacking order it doesn’t matter how big its z-index value is, it can never be positioned in front of an element that belongs to a stacking context with a higher position in the stacking order. As you can see, the position of an element is always relative to its stacking context.
- Elements that have a higher stack level are always positioned in front of the elements with lower stack levels in the stacking context.
- Elements can’t have the same position on the z-axis. However, if there are elements that have the same stack level within a stacking context they are positioned back-to-front depending on the tree order.
Let’s take a look at how this works in codes:
What we’re seeing here are two different stacking contexts that have each one element. Item2 (i.e. the blue element) has a low z-index value (minus 9999999) while Item1 (i.e. the red element) has a very high z-index value (9999999).
Based on the values of the elements you would assume that the red element, aka item 1, is positioned in front of the blue element, aka item 2.
But let’s remember the above-mentioned findings. More specifically that elements are always positioned relative to their stacking contexts. So, for this example, this means: It’s impossible for the red element to have a higher position than the blue one, no matter how high its z-index value. Why? Because its stacking context has a lower position within the stacking order than the stacking context of the blue element.
How to generate a stacking context
It’s essential to understand which groups of elements or child elements can be compared with each other. For this, there are specific rules that we’d like to go through.
With the help of these rules, you’ll understand whether a stacking context is generated. This will then allow you to understand which groups of elements can be compared with each other. And by way of comparison, it’s going to be possible to find out the actual stacking order.
So, first things first, stacking contexts are generated in different ways. Let’s take a look at the many ways you can identify if a stacking context is generated.
- When the element’s tag is HTML
- When the element’s position is absolute or relative and the z-index isn’t <auto>
- When the element’s position is fixed or sticky
- When the element is a flex item
- When the element is a grid item
- When opacity smaller than 1
- When the mix-blend-mode is other than <normal>
- When transform, filter, perspective, clip-path, mask, mask-image and mask-border are other than <none>
- When isolation has the value <isolate>
- When will-change has the value <transform> or <opacity>
- When contain has the value <layout>, <paint>, <strict>, or
But, of course, things are a little bit more complicated than this and here’s why: There are certain elements that are treated as a stacking context even though they aren’t. More specifically, such elements can be mistaken for elements that generate a stacking context themselves when, in reality, they don’t. They are just treated as such.
The difference between a regular stacking context and this type of “wannabe stacking context” lies in the following: Any stacking context generated by the child elements of this “wannabe stacking context” belongs to the parent stacking context and not to this “wannabe stacking context.”
And here’s how a “wannabe stacking context” is generated:
- Elements with a float value other than <none>
- Positioned elements with a z-index value <auto>
- Elements whose display value is <inline-block> or <inline-table>
<div> <div id="div2" style="float: left"> <div id="div3"></div> <div id="div4"></div> <div id="div5"></div> </div> </div>
Let’s paint a clearer picture: Say, for example, you have a root element (#div1) that generates a stacking context. This stacking context includes a floated element (#div2). Now, as you see in our example this floated element has three child elements. One of those child elements (#div3) further generates a stacking context. This stacking context-generating child element belongs to the stacking context generated by the root element mentioned above. The child stacking context of the root element (#div1) are the elements #div2 and #div3.
However, the other child elements (#div4, #div5) of the floated element treat the floated element as the generator of their stacking context.
The order within the stacking context
After learning about how to determine when a stacking context is generated and how to detect elements that seem to be generating a stacking context but aren’t really, it’s important to understand how to figure out which elements are positioned in front of or behind which elements within the stacking context. To do that you have to follow specific rules.
Here are the 6 rules to follow to determine an element’s position in the stacking order:
- Element with a negative z-index
- Block level element (display: block)
- Floated element
- Inline level element (display:inline | inline-block)
- Positioned element with z-index has the value <auto> or <0> or is an element that generates a stacking context
- Element with a positive z-index
Note that every stacking context generating element is a regular element. And its stacking level within its parent stacking context is determined by these rules as well.
To help you better grasp all this, here’s a coding example of how a stacking order works without z-index, so we’re displaying rules number 2, 3, 4, and 5.
Notice that you can change the position of an element via the opacity value because if the value is less than 1 it generates a stacking context.
- Elements are either higher or lower positioned than other elements, they can’t be equally positioned.
- There are groups of elements that move together along the z-axis. Such groups are called a stacking context.
- Every stacking context has a root HTML element, which generates a stacking context.
- Every element belongs to one stacking context.
- The position of an element along the z-axis is relative to the position of their stacking context and is determined by the above mentioned 6 rules. The child elements of a stacking context are always positioned above their stacking context generating element (i.e. root element).
All of this works recursively, meaning that it applies to any element.
Now, we know that this one was a real head-scratcher, but did we solve your problem, or what? Leave a comment and let us know!