CSS · Architecture

Z-Index

When elements overlap — a dropdown over content, a modal over everything — z-index decides which one is on top. It is simple once you understand stacking contexts.

Advanced 6 min Lesson 22 of 26 Runnable examples
Before you start:Positioning
0/26 in CSS
On this page · 6 min · Advanced

Learning objectives#

  • Use z-index to layer overlapping elements
  • Know that z-index needs a positioned element (or flex/grid item)
  • Understand stacking contexts
  • Organise layers with a scale

Explanation#

By default, elements later in the HTML paint on top of earlier ones. z-index changes that: higher numbers come forward.

z-index only works on positioned elements (relative, absolute, fixed, sticky) and on flex or grid children.

A stacking context is a group whose children are layered only among themselves. Properties like opacity < 1, transform, filter, or position + z-index create one.

This is why z-index: 9999 sometimes “does not work”: if its parent is in a lower stacking context, the child can never rise above elements outside that parent.

Keep a small scale of named layers, e.g. dropdown 10, sticky header 20, overlay 30, modal 40, toast 50.

Code example: Layers and the stacking-context trap#

HTMLLayers and the stacking-context trap Runnable
<style>
  :root { --z-header: 20; --z-modal: 40; }
  body { font-family: sans-serif; }
  .box { position: absolute; width: 120px; height: 80px; padding: 6px; color: white; border-radius: 6px; }
  .red   { background: #dc2626; top: 10px;  left: 10px;  z-index: 3; }
  .green { background: #16a34a; top: 40px;  left: 60px;  z-index: 2; }
  .blue  { background: #2965f1; top: 70px;  left: 110px; z-index: 1; }


  .stage { position: relative; height: 170px; }


  .parent { position: relative; z-index: 1; background: #fef3c7; padding: 10px; height: 60px; }
  .child  { position: absolute; z-index: 9999; top: 30px; left: 20px; background: #7c3aed; color: white; padding: 6px; }
  .sibling { position: relative; z-index: 2; background: #fde68a; padding: 10px; height: 60px; }
</style>


<div class="stage">
  <div class="box red">z 3 — on top</div>
  <div class="box green">z 2</div>
  <div class="box blue">z 1 — bottom</div>
</div>


<div class="parent">Parent z-index 1
  <div class="child">Child z-index 9999 — still underneath!</div>
</div>
<div class="sibling">Sibling z-index 2 covers the child</div>
Expected output
Red sits on top of green, which sits on top of blue. Below, the purple child with z-index 9999 is still hidden by the sibling because its parent only has z-index 1.
Opens this example in the full playground

Step-by-step explanation#

  1. Without z-index, blue (last in the HTML) would be on top.
  2. z-index 3, 2, 1 reverses the order.
  3. .parent with position and z-index 1 creates a stacking context.
  4. The child’s 9999 only competes with other children of .parent.
  5. .sibling at z-index 2 beats the whole .parent group, child included.

Real-world use case#

Dropdown menus hidden behind a sticky header, or a modal that appears under a carousel, are classic z-index bugs fixed by understanding stacking contexts.

Common mistakes#

z-index on a static element

A plain block with z-index and no position does nothing. Add position: relative.

z-index: 99999 escalation

Ever-higher numbers hide the real problem: a stacking context. Find the ancestor that creates it.

transform creating unexpected contexts

Adding transform (even for an animation) to a parent creates a stacking context and can trap a dropdown inside it.

Best practices#

  • Use a small, documented z-index scale (CSS variables help)
  • Render modals and toasts near the end of <body>
  • Use DevTools 3D view / Layers panel to inspect stacking
  • Use isolation: isolate to create a stacking context on purpose

Remember this#

Higher z-index = closer to you — but only among siblings in the same stacking context.

No position (or flex/grid parent)? No z-index effect.

A child can never climb higher than its parent’s layer.

Practice exercise#

Your task: A dropdown with z-index: 100 appears behind a sticky header with z-index: 10. The dropdown’s parent .toolbar has position: relative; z-index: 1. Fix it.

Need a hint?
The dropdown is trapped in its parent’s stacking context.
Show solution
CSS Illustrative
/* Raise the parent context above the header (or remove its z-index). */
.toolbar { position: relative; z-index: 11; }

Mini quiz#

Z-Index quizMultiple choice Question 1 of 3

Which element can use z-index?

Score so far: 0/0

Want more? Practise all CSS MCQs · CSS interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.