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

Written in Design by Núria Soriano — June 25, 2020

z-index: 2147483647

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.

Did you know you can code overlapping elements without using z-index at all?

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 z-index controls.

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 relative, absolute, fixed, or sticky.

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:

See the pen on Codepen

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.

See the pen on Codepen

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:

See the pen on Codepen

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.

Stacking contexts

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 z-index to 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 z-index: 1.

See the pen on Codepen

Take-aways

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.
  • Keep z-index values low: you'll rarely need more than z-index: 1 (or less than z-index: -1)
  • Create stacking contexts to keep things boxed and prevent them from interfering with each other.

Further reading