Understanding Z Index: A Complete Guide to CSS Layering

Master the art of controlling element stacking order, from basic z-index usage to advanced stacking context behavior.

What is Z-Index in CSS?

Z-index is one of the most powerful yet frequently misunderstood CSS properties. It controls the vertical stacking order of elements, determining which elements appear in front of and behind others when they overlap.

Think of your webpage as existing in three dimensions: x (horizontal), y (vertical), and z (depth). While x and y positions control where elements sit on the page, z-index controls which elements are closer to the viewer through the screen.

Understanding z-index is essential for creating complex layouts with modals, dropdowns, sticky headers, notification toasts, and visually rich designs. Without it, overlapping elements would stack in source order alone, limiting design possibilities.

In modern web development, z-index plays a critical role in user interface patterns. Modal dialogs rely on high z-index values to appear above all other content. Dropdown navigation menus need proper stacking to float above page content. Hero section overlays position text above background images. Tooltips and hover cards use z-index to appear contextually above their trigger elements. Even sticky headers that remain visible during scrolling depend on z-index to stay above the document content.

Basic Z-Index Syntax
.element {
 z-index: auto; /* Default - same stacking level as parent */
 z-index: 0; /* Explicit layer 0 */
 z-index: 10; /* Positive value - above default */
 z-index: -5; /* Negative value - below default */
}

How Z-Index Works: The Fundamentals

The Critical Position Requirement

Z-index only works on positioned elements. This is the most common misunderstanding about z-index. An element must have a position value other than static for z-index to have any effect.

The position values that activate z-index:

  • position: relative
  • position: absolute
  • position: fixed
  • position: sticky

Default Stacking Behavior

Without z-index, elements stack based on their order in the HTML. Later elements appear on top of earlier ones (source order). Positioned elements automatically stack above non-positioned elements, regardless of where they appear in the markup.

For example, if you have three div elements in source order--first, second, and third--without any z-index values, the third element will appear on top of the second, which appears on top of the first. This behavior can be surprising when layout changes cause previously non-overlapping elements to stack in unexpected ways.

When elements have the same z-index value, the one that appears later in the HTML document takes precedence. This "painters algorithm" approach means the document order determines stacking when no explicit z-index is specified.

Understanding Stacking Contexts

What Creates a Stacking Context?

A stacking context is like an isolated stacking environment. When a new stacking context is created, all descendant elements stack relative to each other, but their z-index values are only meaningful within this boundary. Think of it as a "mini stacking system" contained within a parent element.

An element with z-index: 100 inside a parent with z-index: 1 may not appear above an element with z-index: 2 outside the parent. The child's z-index is relative to the parent's context, not the entire page. This isolation effect is the key to understanding complex z-index behavior.

Properties that create new stacking contexts:

  1. Any positioned element with z-index other than auto
  2. Any element with opacity less than 1 (e.g., opacity: 0.5)
  3. Any element with transform other than none
  4. Any element with filter applied
  5. Any element with clip-path applied
  6. Child elements of flex containers with z-index other than auto
  7. Child elements of grid containers with z-index other than auto
  8. Any element with isolation: isolate

The MDN Web Docs provide authoritative documentation on these stacking context rules, while Ahmad Shadeed's visual guide offers excellent interactive examples demonstrating how stacking contexts work in practice.

Default Stacking Order Within a Context

Within a single stacking context, elements stack from back to front in this specific order:

LayerElement TypeDescription
1Background and bordersOf the stacking context's root element
2Negative z-indexChild elements with negative values (lowest first)
3Non-positioned blocksBlock-level elements in normal flow
4Non-positioned floatsFloated elements without positioning
5Inline elementsText, images, inline-block elements
6Positioned (auto)Positioned elements with z-index: auto
7Positive z-indexPositioned elements with positive values (lowest first)

This layered approach means that an element with z-index: -1 will appear behind the parent's background but in front of the parent's content. Elements with negative z-index values stack in ascending order--z-index: -2 appears behind z-index: -1.

Common Z-Index Problems and Solutions

Problem 1: Z-Index Not Working

Symptoms: You've set z-index but elements still don't stack as expected.

Solutions:

  1. Check if the element has a position value set (not static)
  2. Check if a parent element has created a stacking context via opacity, transform, etc.
  3. Use browser DevTools to inspect the stacking context hierarchy

Problem 2: Element "Trapped" in Parent Context

Symptoms: A dropdown menu inside a header appears behind page content even with high z-index.

Cause: The parent created a stacking context, limiting the child's effective z-index. For example, if the header has opacity: 0.9 or transform: translateX(0), it creates a new context that bounds the dropdown's z-index.

Solutions:

  • Apply z-index to the parent container instead of the child
  • Remove the parent element's stacking context property (if possible)
  • Move the child outside the stacking context in the HTML structure

Problem 3: Negative Z-Index Hiding Elements

Symptoms: Elements with negative z-index disappear behind the parent's background.

Explanation: Elements with negative z-index are stacked behind the parent's content but still in front of the parent's background and border. If you need an element to appear behind everything, you may need to restructure the HTML or adjust the parent's stacking context.

Debugging Workflow

When z-index issues arise, follow this systematic approach:

  1. Verify positioning - Open DevTools and confirm the element has a non-static position value
  2. Identify parent contexts - Check ancestors for opacity, transform, filter, or clip-path that might create stacking contexts
  3. Calculate effective z-index - Use DevTools to see the element's position within its local stacking context
  4. Adjust the appropriate level - Either modify the local element or adjust the parent context to achieve the desired stacking

For teams working on professional web development projects, establishing clear z-index conventions from the start prevents these common issues from affecting production code.

Practical Z-Index Patterns

Pattern 1: Modal Overlays

Full-screen modals must appear above all other content:

.modal-overlay {
 position: fixed;
 z-index: 1000;
 inset: 0;
}
.modal-content {
 position: relative;
 z-index: 1001;
}

Pattern 2: Sticky Header Navigation

Headers that stay above page content while scrolling:

.header {
 position: sticky;
 z-index: 50;
 top: 0;
}

Pattern 3: Dropdown Menus

Nested menus that appear above sibling content:

.dropdown {
 position: relative;
 z-index: 10;
}
.dropdown-menu {
 position: absolute;
 z-index: 20;
}

Pattern 4: Card Overlays

Cards with content floating above background images:

.card {
 position: relative;
}
.card-content {
 position: relative;
 z-index: 1;
}
.card-background {
 position: absolute;
 z-index: 0;
}

Pattern 5: Notification Toasts

Toast notifications that appear above most content:

.toast {
 position: fixed;
 z-index: 500;
 bottom: 1rem;
 right: 1rem;
}

Pattern 6: Tooltips

Small contextual popups that appear above surrounding content:

.tooltip {
 position: absolute;
 z-index: 100;
}

Z-Index Best Practices

Organize Your Z-Index Scale

Avoid arbitrary numbers. Use a systematic approach with CSS custom properties:

:root {
 --z-dropdown: 100;
 --z-sticky: 200;
 --z-modal-backdrop: 300;
 --z-modal: 400;
 --z-toast: 500;
 --z-loading: 600;
}

Avoid Magic Numbers

Z-index values like 9999 or 99999 indicate design problems:

  • They suggest uncertainty about the z-index hierarchy
  • They make maintenance difficult when adding new components
  • They can conflict with third-party code libraries
  • A well-organized scale makes your intent clear to other developers

Use Semantic Naming

Name z-index values by purpose, not by level:

  • --z-dropdown instead of z-100
  • --z-modal instead of z-999
  • Makes code self-documenting and easier to understand
  • New team members can immediately understand component layering intent

Test in Context

Test z-index behavior with:

  • Parent containers that have transforms applied
  • Opacity changes for hover states or animations
  • Different viewport sizes on various devices
  • Nested components with multiple z-index levels
  • Browser DevTools stacking context visualization features

Document Your Scale

For larger projects, create a documentation comment or style guide that explains your z-index scale:

/*
 Z-Index Scale
 ============
 0-99: Base elements (cards, content blocks)
 100-199: Tooltips, popovers, dropdowns
 200-299: Sticky headers, navigation
 300-399: Modal backdrops
 400-499: Modal content
 500+: Notifications, loading overlays
*/

Following these CSS best practices ensures your layering code remains maintainable as projects grow in complexity.

Z-Index Quick Reference
ScenarioZ-Index NeededPosition Required
Dropdown menuYes (e.g., 10-20)Yes (relative or absolute)
Sticky headerYes (e.g., 50)Yes (sticky or fixed)
Modal overlayYes (e.g., 400-500)Yes (fixed)
TooltipYes (e.g., 50-100)Yes
Notification toastYes (e.g., 500+)Yes (fixed)
Hover effects onlySometimesUsually
Background elementNegativeYes

Frequently Asked Questions

Ready to Build Better Web Experiences?

Our team creates custom websites with clean, maintainable CSS architecture. From complex layouts to performance optimization, we build with best practices from day one.