Why z-index: 9999 Is an Anti-Pattern
Understanding why using arbitrarily high z-index values like 9999 or 999999 creates maintenance problems and how to replace them with a proper scale.
Detailed Explanation
The z-index: 9999 Problem
Using arbitrarily high z-index values is one of the most common CSS anti-patterns. It seems like a quick fix but creates cascading problems as a project grows.
How It Starts
/* Developer A: "I need this above the header" */
.modal { z-index: 999; }
/* Developer B: "My modal needs to be above that one" */
.important-modal { z-index: 9999; }
/* Developer C: "The tooltip needs to be on top of everything" */
.tooltip { z-index: 99999; }
/* Developer D: "I need this REALLY on top" */
.critical-alert { z-index: 999999; }
/* The codebase 6 months later... */
.the-thing-that-must-not-be-named { z-index: 2147483647; }
/* (That's the max 32-bit integer) */
Why It Fails
No ceiling: There is always a higher number. When two developers independently add high values, conflicts are inevitable.
No semantic meaning:
z-index: 9999communicates nothing about what the layer is or where it should sit in the hierarchy.Stacking contexts nullify it: Even
z-index: 2147483647is trapped inside its stacking context. If the parent hasz-index: 1, it cannot exceed another element withz-index: 2.Hard to debug: Finding all z-index values scattered across a codebase and understanding their relationships is extremely difficult.
The Fix: Define a Scale System
/* Before: arbitrary values */
.dropdown { z-index: 100; }
.header { z-index: 500; }
.modal-bg { z-index: 999; }
.modal { z-index: 9999; }
.tooltip { z-index: 99999; }
/* After: deliberate scale */
:root {
--z-dropdown: 1000;
--z-sticky: 1020;
--z-overlay: 1040;
--z-modal: 1050;
--z-toast: 1080;
--z-tooltip: 1090;
}
.dropdown { z-index: var(--z-dropdown); }
.header { z-index: var(--z-sticky); }
.modal-bg { z-index: var(--z-overlay); }
.modal { z-index: var(--z-modal); }
.tooltip { z-index: var(--z-tooltip); }
Migration Strategy
- Audit: Search your codebase for all z-index declarations
- Categorize: Group them by purpose (dropdown, modal, tooltip, etc.)
- Design scale: Use this tool to create a proper z-index scale
- Replace: Swap hardcoded numbers for CSS variables
- Lint: Add a CSS linter rule to prevent hardcoded z-index values
ESLint / Stylelint Rule
// stylelint-plugin-no-hardcoded-zindex (conceptual)
"declaration-property-value-disallowed-list": {
"z-index": ["/^[0-9]+$/"]
}
Use this tool to design your z-index scale before writing a single line of CSS.
Use Case
When inheriting a codebase with scattered z-index values and need to refactor to a consistent, maintainable scale system, or when setting up CSS guidelines for a new project.