Why we never use z-index

Alfred Yang
finnovate.io
Published in
3 min readJul 27, 2023
Photo by Hoach Le Dinh on Unsplash

Have you ever added a CSS z-index to a div just to find out (a few days later) that your div is showing up in unexpected places? This is exactly why we made it a priority to avoid z-indices.

z-indices are especially difficult to manage in large code bases where multiple developers are involved. Developers keep trying to “overpower” z-indices introduced by other developers. Before you know it, someone decides to add a z-index of 9,999 thinking that it will conquer all — that is until someone else decides to do a z-index of 10,001, because somehow, 10,001 is more effective than 10,000.

It is absolutely ridiculous.

Z-index can be avoided in the vast majority of cases

Consider natural rendering order of HTML

Z-index is unnecessary the majority of the time if we simply take a minute to think about the natural rendering order of the DOM. Browsers render elements top-down, meaning that elements lower in the DOM will naturally appear on top of a element defined higher up if the two overlap.

Consider this example:

<div style="position: relative">
<div style="z-index: 1; background-color: yellow; width: 200px; height: 200px; position: absolute">
Yellow
</div>
<div style="background-color: red; width: 400px;height: 400px; position: absolute">
Red
</div>
</div>

We have a yellow square and a red square. We added a z-index of 1 so that the yellow square appears on top. However, we can achieve the exact same outcome by simply rearrange the order of the div’s and getting rid of the z-index.

<div style="position: relative">
<div style="background-color:red;width: 400px;height: 400px; position: absolute">
Red
</div>
<div style="background-color:yellow;width: 200px;height: 200px; position: absolute;">
Yellow
</div>
</div>

Render elements that need to be on top in higher level components

If you are building an app with components, consider mounting components that need to appear above other components higher up in the component hierarchy.

It is best to illustrate with an example:

// pseudo code, don't try this at home
<container>
Some content...

<component1>
<modal z-index={100}>
This is a modal
</modal>
<button onClick={showModal()} />
</component1>

</container>

In this case you want the modal to appear on top of “some content” in the outer container. A lazy way to do this would be to add a high z-index on the modal hoping that no one else will introduce a higher z-index somewhere else…. we all know that’s wishful thinking.

A better way is to simply mount the modal in the container itself letting the natural DOM rendering order do its thing:

// pseudo code, don't try this at home
<container>
Some content...

<component1 onButtonClick={showModal()}>
<button onClick={onButtonClick()} />
</component1>

<modal>
This is a modal
</modal>

</container>

If you do end up using z-index, make sure you understand stacking context

In the vast majority of cases, z-indices can be avoided. Avoid them if possible. If you do decide z-indices are needed, make sure every developer on your team understands CSS stacking context. A few key points:

  • A positioned element (i.e. position: absolute, relative) WITH a non-auto z-index has its own stacking context. This means z-indices of child elements do not take effect outside of the positioned element. There are other cases when elements has its own stacking context, but this is the most common one.
  • By default, a html element has a z-index of “auto”, which evaluates to 0. This is different from explicitly defining a z-index of 0 due to the above point regarding stacking context.
  • Stick with one, at most two z-index values across the entire app. (i.e. 1 and -1).

--

--

Alfred Yang
finnovate.io

Alfred is the founder of https://finnovate.io, a company that focuses on helping organizations build unique digital experiences on web, mobile and blockchain.