References

Beginner-friendly references for web development, with live, editable examples.

The CSS z-index property

Property CSS All modern browsers Updated
Quick answer

The CSS z-index property sets the stacking order of overlapping elements — a higher number sits in front of a lower one. It only works on elements with a position other than static (or on flex/grid items). If z-index seems to do nothing, a missing position is almost always why.

Overview

z-index decides which element wins when boxes overlap — think a dropdown that needs to sit above the content, or a modal above everything. A higher value is closer to the viewer, a lower value further back. Negative values are allowed and push an element behind its siblings.

The single most common gotcha: z-index has no effect on a statically-positioned element, which is the default. The element needs position set to relative, absolute, fixed or sticky first (flex and grid items are an exception and respond to z-index directly). If you have set a sky-high z-index and nothing moved, check the position.

The deeper concept is stacking contexts. Certain properties — a positioned element with a z-index, any element with an opacity below 1, a transform, and others — create a new, self-contained stacking world. A child's z-index only competes within its context, never against elements outside it. That is why a z-index of 9999 sometimes still loses: it is trapped in a context that, as a whole, sits behind its rival.

Syntax

selector {
  position: relative; /* or absolute, fixed, sticky */
  z-index: 10;
}

Values

The z-index property accepts the values below. Every property also accepts the CSS-wide keywords inherit, initial, revert and unset.

Value Description
auto The default. The element stacks in normal order without forming a new layer.
0 A baseline stacking level, on the same plane as auto siblings.
positive Higher numbers sit in front, e.g. z-index: 10. Use sparingly and consistently.
negative Pushes the element behind its siblings, e.g. z-index: -1.

Example

Live example
<style>
  .stack { position: relative; height: 120px; font: 600 14px system-ui, sans-serif; }
  .stack div { position: absolute; width: 90px; height: 70px; border-radius: 10px; display: flex; align-items: center; justify-content: center; color: #fff; }
  .back { left: 30px; top: 10px; background: #94a3b8; z-index: 1; }
  .front { left: 70px; top: 30px; background: #1c7ce9; z-index: 2; }
</style>
<div class="stack">
  <div class="back">z: 1</div>
  <div class="front">z: 2</div>
</div>

Best practices

  • Remember z-index needs a non-static position (or a flex/grid parent). No position, no effect.
  • Use a small, agreed scale (say 10, 100, 1000 for dropdowns, sticky bars, modals) instead of escalating to 9999 — that war never ends well.
  • When a high z-index still loses, look for a parent forming a stacking context with opacity, transform or a z-index of its own.
  • Keep z-index values documented or tokenised in larger projects so layering stays predictable across components.

Frequently asked questions

Why is z-index not working?
Most often the element has the default position: static, on which z-index has no effect. Give it position: relative (or absolute/fixed/sticky) and the z-index will apply.
What is a stacking context?
A self-contained layer in which child z-indexes are compared only against each other. Properties like a positioned z-index, an opacity below 1, or a transform create one — which is why a huge z-index can still sit behind another element.
Can z-index be negative?
Yes. A negative z-index pushes a positioned element behind its siblings, and potentially behind its parent's background, which is occasionally useful for decorative layers.
How high should a z-index be?
As low as it needs to be. Use a consistent scale across your project rather than arbitrary large numbers — reaching for 9999 usually signals a stacking-context problem, not a value that is too small.