🌱BeginnerCSS Layout Basics

CSS Z-index and Stacking

Control which elements appear on top using z-index and understand how stacking contexts work.

Overview

When elements overlap on a page, CSS decides which one appears on top using a concept called stacking order. The `z-index` property lets you control this order explicitly. By default, elements are painted in this order (back to front): block elements → floats → inline elements → positioned elements. Positioned elements (anything except static) already appear on top of non-positioned ones. **z-index** only works on positioned elements (position: relative, absolute, fixed, or sticky). Higher z-index values appear on top of lower ones within the same stacking context. A **stacking context** is an independent layer on the page. Creating one isolates z-index values a z-index: 9999 inside a stacking context cannot appear above elements outside that context. Stacking contexts are created by: position + z-index, opacity < 1, transform, filter, and others.

Key Points

  • •z-index only works on positioned elements (not static)
  • •Higher z-index = closer to viewer (on top)
  • •z-index: auto element participates in parent stacking context without creating a new one
  • •Stacking contexts isolate z-index: child z-index only competes within the parent context
  • •Common triggers for new stacking context: position+z-index, opacity<1, transform, filter
  • •Use small z-index values (1, 2, 10, 100) avoid huge arbitrary values like 99999

Examples

Basic z-index ordering

.card {
  position: relative;
  z-index: 1;
}

.modal {
  position: fixed;
  z-index: 100;   /* always on top of cards */
}

.dropdown {
  position: absolute;
  z-index: 50;    /* above cards, below modals */
}

Establish a z-index scale: cards (1–9), dropdowns (10–49), modals (100–199), toasts (200+).

The stacking context trap

.parent {
  position: relative;
  opacity: 0.9;      /* creates a stacking context! */
}

.child {
  position: absolute;
  z-index: 9999;     /* high z-index, but only within .parent's context */
}

/* .child cannot appear above elements outside .parent,
   no matter how high its z-index is */

opacity < 1 creates a new stacking context. This is the most common source of z-index confusion.

Practical z-index scale

/* Define your z-index scale as custom properties */
:root {
  --z-base:    1;
  --z-dropdown: 10;
  --z-sticky:  20;
  --z-overlay: 30;
  --z-modal:   40;
  --z-toast:   50;
}

.modal { z-index: var(--z-modal); }

Common Mistakes

  • Setting z-index on a static (position: static) element has no effect
  • Using z-index: 9999 to "fix" layering usually means a stacking context is the real problem
  • Not realizing opacity < 1, transform, and filter create new stacking contexts

Note

When z-index is not working, first check: (1) Is the element positioned (not static)? (2) Is there a stacking context ancestor (opacity, transform, filter) that is isolating it?

Exercises

Write CSS to style the HTML scaffold. The preview updates live — when it looks right, mark as done.

Loading editor…

Completed: 0 / 5 exercises

Knowledge Check

Question 1 of 4

On which type of element does z-index have no effect?