How to Manage Z-index

Introduction

Recently, I came across an article: Never Get Bit by z-index Again🔗, where the author mentioned using CSS Variables to assign relative rather than absolute z-index values, which is an elegant and concise method! It perfectly leverages the advantages of CSS variables.

Background

In many cases, we need to adjust the z-index of different elements to ensure that their display order during overlap is correct. However, using fixed values often leads to code fragility, especially in large projects, where different parts may cause tracking and maintenance issues due to z-index conflicts. Typically, a specification file is set up to standardize values, such as Bootstrap’s z-index defined as follows:

dropdown: 1000;
sticky: 1020;
fixed: 1030;
modal-backdrop: 1040;
offcanvas: 1050;
modal: 1060;
popover: 1070;
tooltip: 1080;

However, any modification to the code requires checking this table and ensuring that our values do not conflict with other elements. Continuous maintenance is needed to ensure the correctness of individual value relationships:

  1. The document and code must be synchronized.
  2. We need to ensure the correct weight between values at all times.

Solution

1. Solving the Code and Document Synchronization Issue

Fortunately, native CSS variables have great support🔗 today, allowing us to define z-index values directly through CSS variables, solving the issue of needing additional documents, preprocessors, or even JavaScript for management.

:root {
--dropdown-zindex: 1;
}
.dropdown {
/* Directly reference the defined value in CSS \O/ */
z-index: var(--dropdown-zindex);
}

2. Solving the Weight Issue Between Values

By using CSS variables, we can directly reference variables in the code without needing to check the document. However, we still need to ensure the correct weight between values. At this point, we can use CSS calc()🔗 to solve this problem.

:root {
--dropdown-zindex: 1;
--sticky-zindex: calc(var(--dropdown-zindex) + 1);
}

Why +1? Because z-index must be an integer, so we can use +1 to ensure that sticky is always above dropdown. Of course, this value can also be abstracted for unified definition.

:root {
--gap-zindex: 10;
--dropdown-zindex: 1;
--sticky-zindex: calc(var(--dropdown-zindex) + var(--gap-zindex));
}

In this way, we have established a simple z-index management system using completely native methods, without the need for additional documents, preprocessors, or JavaScript—just a little CSS variable and calculation will suffice.

Conclusion

Assigning relative relationships rather than absolute values allows us to strongly connect the relationships between elements, rather than relying on a magic number.

Compared to giving absolute values, managing z-index through relative relationships allows me to focus more on “which elements this element will be placed between” rather than memorizing a fixed number, returning to the original intention of using z-index.

Further Reading