Stop (ab)using z-index
Understand how z-index works, when to use it, and why you'll rarely need more than z-index: 1
I once saw this in a codebase. The number seemed so random that I thought it couldn't be that random, so I googled it. Turns out it's the highest value that the
z-index property supports!
That developer must have been really desperate, but it's very common to see things like
z-index: 9999, and if that doesn't work, let's keep adding
9s until it does. You can guess what happens when you try to position something above that.
There are good solutions like creating a z-index scale, which puts a bit sanity into the z-index nonsense, and we use this solution here at Codegram. But most of the time we don't even use the property at all, and when we use it we only use a couple of values. If you find yourself using more, either you have an extremely complex design that is very different from most sites in the internet (not likely), or you are using it wrong.
How z-index works
When working with CSS, we usually deal with two dimensions. However, when elements overlap and we need to adjust their order, we have to deal with a third dimension, the Z axis that the property
Positioning and order
Let's go over the basics: the
z-index is a property related to positioning. By default, all elements have a
static position. In order for
z-index to have any effect at all, it needs to be applied to a positioned element, that means, an element with position
If you don't apply a
z-index, the elements will be stacked in the order they are written in the HTML. Check this example:
The text is not positioned, so it's behind everything. The other elements stack above each other in the order they are written in the HTML.
If we want this to match the design, we could add a
z-index: 1 to the illustration, and
position: relative and
z-index: 2 to the
.hero__title element. It's a good idea to always start with the lowest
z-index value you can, to keep things simple.
But when working with CSS, it's always best if we can rely on the natural order of the elements and avoid altering the flow ourselves, to keep our code simple and scalable. As long as it makes sense, we could adjust the order of the items in the HTML, placing the text as the last element, and by applying
position: relative to it, it wouldn't be necessary to use
z-index at all:
Of course, this approach has certain limitations, sometimes it is not possible to change the HTML, and changing the order arbitrarily should only be done to elements that don't have meaning, so we don't alter the experience of users who use screen-readers.
You can read more about stacking without the z-index property at the MDN web docs.
Following the previous example, let's imagine that it's part of an external library and we do not have control over the code, we cannot alter its HTML or CSS and, to make things worse, the
.hero__title element has a
z-index: 9999. Now, let's say we need to add a modal to the same page. Which
z-index value do you think the modal should have?
Your first reaction might be: oh dear, I should increase that modal
99999, otherwise it will fall below the title, and here they come, the bad practises we wanted to avoid in the first place. But we can avoid this:
z-index only competes with sibling elements within the same stacking context.
Even if the
.hero__title has a
z-index: 9999, we can place it inside a container with
position: relative and
z-index: 1, creating a new stacking context. Each stacking context is completely independent of its siblings: the descendants from each context will not interfere with elements outside. This way, we can position the modal above the hero just by adding a
To sum up, always keep in mind these tips when positioning elements:
- Understand how stacking works, and use the rules to your advantage to avoid using
z-index, as long as it makes sense.
z-indexvalues low: you'll rarely need more than
z-index: 1(or less than
- Create stacking contexts to keep things boxed and prevent them from interfering with each other.