CSS Z-Index

In standard web design, elements are usually laid out in two dimensions: horizontal and vertical. However, the z-index property introduces a third dimension: depth. This depth is represented by the z-axis, which runs perpendicular to your screen.

The z-index property controls the stacking order of elements that overlap. It determines which elements appear "closer" to the user and which ones appear "further away" (behind other elements).

Watch Out: The z-index property only works on elements that have a position value other than static. If your z-index isn't working, check if you've set position: relative;, absolute;, fixed;, or sticky;.

Syntax

/* Using an integer value */
.modal-overlay {
  z-index: 100;
}

/* Using the default value */
.background-element {
  z-index: auto;
}

Values

  • auto: The default value. The element's stack level is the same as its parent, and it does not create a new stacking context.
  • number: An integer (e.g., 0, 10, -5). Elements with a higher number sit in front of elements with a lower number. Negative values are perfectly valid and move an element behind its parent or other elements in the same context.
Best Practice: Avoid using massive numbers like z-index: 999999;. Instead, use a consistent scale (like 10, 20, 30) or CSS variables to manage your layers. This makes your code much easier to maintain as your project grows.

Stacking Context

A stacking context is a three-dimensional grouping of HTML elements. You can think of a stacking context like a folder. Everything inside that folder stays together. Even if a "file" inside Folder A has a z-index of 999, it will still appear behind Folder B if Folder B is stacked higher than Folder A.

A new stacking context is formed when an element meets certain criteria:

  • It is the root element (<html>).
  • It has a position other than static AND a z-index other than auto.
  • It has an opacity value less than 1.
  • It uses CSS properties like transform, filter, perspective, or clip-path.
  • It is a child of a flex or grid container with a z-index value set.
Common Mistake: Thinking a higher z-index will always bring an element to the front. If the element is trapped inside a low-level stacking context (a "folder" that is behind another), no amount of z-index will bring it to the very top of the page.

Examples

Basic Usage: Creating Overlays

In this scenario, we have two absolute-positioned boxes. Since .box2 has a higher z-index, it will overlap .box1 regardless of their order in the HTML.

<div class="box1">Box 1 (z-index: 1)</div>
<div class="box2">Box 2 (z-index: 2)</div>

<style>
  .box1 {
    position: absolute;
    left: 20px;
    top: 20px;
    width: 100px;
    height: 100px;
    background-color: #ff4757;
    z-index: 1;
  }
  .box2 {
    position: absolute;
    left: 60px;
    top: 60px;
    width: 100px;
    height: 100px;
    background-color: #2f3542;
    color: white;
    z-index: 2;
  }
</style>

Negative z-index: Background Decorations

Negative values are often used to place decorative elements (like background shapes or watermark text) behind the main content of a container.

<div class="container">
  <div class="background-shape"></div>
  <p>Main content text is here!</p>
</div>

<style>
  .container {
    position: relative;
    padding: 20px;
    background: white;
  }
  .background-shape {
    position: absolute;
    top: 0;
    left: 0;
    width: 50px;
    height: 50px;
    background-color: #eccc68;
    z-index: -1; /* This moves it behind the text */
  }
</style>

Stacking Context Example

This example demonstrates why nesting matters. The .parent creates a boundary. Even if .child1 has z-index: 9999, it would still be trapped within the parent's layer relative to other elements on the page.

<div class="parent">
  <div class="child1">Child 1 (z-index: 2)</div>
  <div class="child2">Child 2 (z-index: 1)</div>
</div>

<style>
  .parent {
    position: relative;
    width: 200px;
    height: 200px;
    background-color: #f1f2f6;
    z-index: 1; /* New stacking context formed here */
    border: 1px solid #ccc;
  }
  .child1 {
    position: absolute;
    width: 80px;
    height: 80px;
    background-color: #7bed9f;
    z-index: 2;
  }
  .child2 {
    position: absolute;
    width: 80px;
    height: 80px;
    background-color: #70a1ff;
    top: 40px;
    left: 40px;
    z-index: 1;
  }
</style>
Developer Tip: Use your browser's DevTools (like Chrome Inspection) to debug layers. Some browsers have a "Layers" panel or 3D view that lets you visualize the stacking order of your site in real-time.

Important Considerations

  • Layering Contexts: Think of stacking contexts as "local" rules. A high z-index inside a "back" container will never beat a low z-index inside a "front" container.
  • Natural Order: If two elements have the same z-index, the one that appears later in the HTML code will be drawn on top.
  • Opacity and Transforms: Be aware that setting opacity: 0.9 or using transform: scale(1) on an element will trigger a new stacking context, which might change how your z-index behaves unexpectedly.

Mastering z-index is less about memorizing numbers and more about understanding the hierarchy of your layout. Once you grasp how stacking contexts isolate elements, you can build complex UI components like modals, dropdowns, and tooltips with confidence.