UI/UX Atlas
Visual Design Foundational

Depth, Elevation & Layering

Master how shadows, blur, z-order, and surface treatment create a believable three-dimensional space that guides attention and communicates hierarchy.

8 min read

Interactive example · Depth & elevation
Surface · level 2

Higher elevation = larger, softer shadows and more separation from the background. In dark mode, prefer raising surface lightness over shadows, which are nearly invisible on dark backgrounds.

The full lesson

Screens are flat, but our minds think in space. The moment you add a modal, a floating toolbar, or a sticky header, you are building a stack of layers. Users have to mentally navigate that stack. Getting it right — using shadow, blur, opacity, and surface color — makes an interface feel organized and trustworthy. Getting it wrong makes it feel cluttered and confusing.

Depth and elevation are not decoration. They are a communication system. They signal “this is temporary,” “this blocks everything else,” or “this belongs in the background.” Understanding the principles lets you make intentional choices instead of blindly copying shadows from a library.

What Elevation Actually Communicates

Elevation is how far a surface appears to float above the base canvas. Higher elevation means the surface feels closer to the viewer — and therefore more important, more temporary, or more interruptive.

Three things communicate elevation:

  • Shadow: simulates light blocked by a raised surface; larger, softer shadows read as higher elevation
  • Surface color: in light themes, higher surfaces tend to be lighter; in dark themes, they carry a lighter tint (called luminance-step elevation)
  • Blur / backdrop-filter: a frosted-glass effect implies the surface floats above blurred content beneath it

None of these signals works alone. A well-designed elevation system uses all three together so the cues reinforce each other.

The Elevation Scale: Levels 0–5

Most design systems define five to seven named elevation levels. Here is a minimal but expressive scale:

LevelNameTypical useShadow description
0FlatBody, cards at rest, table rowsNo shadow
1RaisedResting cards, chips, badges1–2 px offset, very low spread
2OverlayDropdowns, popovers, tooltips4–8 px offset, medium spread
3ModalDialogs, drawers, sheets12–24 px offset, large spread
4StickyFloating action buttons, sticky headers6–12 px, wide soft spread
5Scrim + modalFull-screen overlays with backdropCombined surface color + scrim

The gaps between levels matter as much as the levels themselves. If a dropdown and a dialog cast the same shadow, users cannot tell the difference between “pick an option” and “this blocking task requires action.”

Expressing the scale with design tokens

W3C DTCG-format tokens keep elevation values consistent across platforms. Here is an example:

{
  "$type": "shadow",
  "elevation-1": {
    "$value": "0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.08)"
  },
  "elevation-2": {
    "$value": "0 4px 8px rgba(0,0,0,0.16), 0 2px 4px rgba(0,0,0,0.12)"
  },
  "elevation-3": {
    "$value": "0 12px 24px rgba(0,0,0,0.20), 0 4px 8px rgba(0,0,0,0.14)"
  }
}

Using semantic names like elevation-1 and elevation-2 instead of raw shadow values means a theme switch — say, from light to dark — only needs to redefine the token values. You do not have to hunt down every shadow declaration in the codebase.

Shadows in Light Themes vs. Dark Themes

The most common mistake when adapting a light-theme system to dark mode is keeping drop shadows unchanged. On a dark background, dark shadows are invisible — they disappear into the surface.

Outdated approach: invert the hex background colors, keep the same rgba shadow values. The interface looks flat and unlayered on dark surfaces.

Modern approach: in dark themes, communicate elevation primarily through surface lightness — this is luminance-step elevation. Give higher surfaces a slightly lighter fill. A few percentage points of white overlay is enough. You can still use shadows, but make them lighter or brand-color tinted at low opacity. Use a near-black like #0A0A0A for the background rather than pure #000000. Pure black creates harsh contrast that amplifies any layering inconsistency.

Do

Use luminance-step elevation in dark themes: apply a subtle white-tinted surface overlay (e.g., 4–8% opacity) to raised surfaces so the elevation hierarchy stays visible without relying on shadows.

Don't

Don’t simply invert your light-theme surface colors or keep the same dark-colored drop shadows on a dark background. Shadows disappear into dark surfaces and elevation collapses to a single flat layer.

Layering and Z-Order: The Stacking Model

Z-order is the sequence of layers from farthest to nearest. Defining this sequence explicitly — in code and in your design system docs — prevents the “modal appearing behind a tooltip” class of bugs that shows up in every production codebase eventually.

A practical layer taxonomy, ordered from bottom to top:

  1. Base canvas — the page body, background images
  2. In-flow content — cards, sections, articles
  3. Sticky UI — sticky headers, floating action buttons
  4. Dropdowns and popovers — menus, date pickers, select panels
  5. Modals and drawers — dialogs that take focus
  6. Scrims — full-viewport overlays that dim lower layers
  7. Notifications — toasts and banners that appear above everything, including modals

In CSS this maps to a z-index scale. The exact numbers matter less than the fact that they come from named tokens:

:root {
  --z-sticky: 100;
  --z-dropdown: 200;
  --z-modal: 300;
  --z-scrim: 350;
  --z-notification: 400;
}

Using CSS custom properties for z-index values lets you reason about the entire stack in one place. It prevents the “z-index: 9999” arms race that happens when each developer patches conflicts locally.

Stacking contexts and common gotchas

A stacking context is a self-contained layer group in the browser. It forms whenever an element has position other than static combined with a z-index value, or uses transform, opacity below 1, filter, isolation: isolate, or will-change with certain values.

Once a child is inside a stacking context, its z-index is relative to that context — not the document root.

This is the cause of the classic “modal appears behind sidebar” bug. The modal renders inside a transform-animated container. That container created a new stacking context, so the modal’s z-index: 300 only competes within that container rather than the full page. Diagnose these issues in browser DevTools using the 3D view (Firefox) or the Layers panel (Chrome).

Blur, Frosted Glass, and Backdrop Filter

backdrop-filter: blur() creates the frosted-glass effect. The surface blurs whatever is rendered beneath it, implying it floats above the content. It is visually powerful but comes with real costs:

  • Performance: backdrop-filter triggers compositing on every repaint of the content beneath. On content-heavy or animated backgrounds it can cause frame drops, especially on lower-end hardware.
  • Accessibility: heavy blur over text can reduce effective contrast for users with low vision.
  • Prefix requirement: the -webkit-backdrop-filter vendor prefix is still required for some older WebKit builds as of 2026.

Use it with restraint. Frosted glass works best for sidebars, command palettes, and modals where the blurred area is relatively small. Avoid applying it to elements that scroll over densely animated content.

.surface-elevated {
  background: oklch(99% 0 0 / 0.72);
  backdrop-filter: blur(16px) saturate(180%);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
}

Note the use of OKLCH for the background color. OKLCH is a color format designed for perceptual uniformity — equal numerical steps produce equal-looking lightness changes. This makes it far easier to produce the subtle near-white tints frosted surfaces require, compared to hex or HSL where lightness adjustments can cause unexpected hue shifts.

Scrim and Focus Management

A scrim is a semi-transparent overlay that dims the entire viewport behind a modal or drawer. It communicates: “the rest of the interface is temporarily unavailable.” Scrims serve two purposes — visual (isolating the foreground content) and behavioral (intercepting clicks outside the dialog to close it or prompt the user).

Design considerations for scrims:

  • Opacity: 40–60% black is the conventional range. Too light and the scrim fails to isolate. Too dark and it feels like the interface crashed.
  • Animation: the scrim should fade in, not pop. A 150–200 ms ease-out fade is barely perceptible but makes the transition feel smooth.
  • Focus trapping: while a modal is open, keyboard focus must stay confined inside it. In 2026 the inert attribute is the correct mechanism — apply inert to all siblings of the modal root rather than manually intercepting Tab keypresses. This satisfies WCAG 2.2 criterion 2.1.2 (No Keyboard Trap) without brittle JavaScript.
<div id="app-root" inert aria-hidden="true">
  <!-- page content, inaccessible while modal is open -->
</div>
<dialog id="confirm-modal" open>
  <!-- modal content, focus stays here -->
</dialog>

Layering in Component Systems

Elevation and layering problems compound quickly in component systems because components are built by multiple teams. Two practical mitigations:

Use isolation: isolate defensively

When you build a component that might receive arbitrary z-indexed children — a card, a section wrapper, a data table row — add isolation: isolate to the component root. This creates a scoped stacking context. It prevents child z-index values from leaking out and competing with global-level layers like modals. It has no visual effect; it is purely structural.

Document the layer contract

Every component that affects the stacking model should document its expected layer, the z-index token it uses, and whether it creates a new stacking context. A Storybook story that renders the component alongside a modal is a cheap way to catch layer conflicts during development rather than in production.

Elevation Tokens in Practice

A three-tier token architecture keeps the elevation system coherent:

  • Primitive tokens — raw shadow values: shadow-sm, shadow-md, shadow-lg
  • Semantic tokens — meaningful names: elevation-card, elevation-dropdown, elevation-modal
  • Component tokens — component-specific aliases: card-shadow, dialog-shadow

Semantic tokens reference primitives. Component tokens reference semantics. When a theme change is needed — for example, making the dark theme use luminance-step instead of shadows — you only update the semantic token definitions. Every component inherits the change automatically.

This mirrors the W3C DTCG stable format ($value / $type) and is the approach used by Material Design 3, Apple’s HIG layering model, and most mature design systems today.

Common Mistakes and How to Fix Them

MistakeSymptomFix
No elevation cues at allUsers cannot distinguish interactive from static surfacesAdd even a 1 px offset shadow to clickable cards; use surface color contrast
Overusing heavy shadowsInterface looks dramatic; visual noise everywhereLimit distinct elevation levels to 3–4; only the highest layer needs a large shadow
Identical shadow on dropdown and modalUsers cannot tell if they are blocked or choosingAssign distinct elevation levels; modals should be visually heavier than popovers
Dark mode shadows invisibleLayering hierarchy collapses in dark themeSwitch to luminance-step elevation; use near-black base, not pure black
z-index arms raceModals behind navbars; tooltips clippedDefine a global z-index token scale; use isolation: isolate on component roots
backdrop-filter on animated contentFrame drops and jankRemove blur from surfaces that scroll over animated backgrounds