Layered box-shadow CSS: offset, blur, spread, and inset

Published: 2026-09-05

How CSS box-shadow offset, blur, spread, color, and inset work—and how stacking layers builds soft cards, glows, and pressed UI without images.

box-shadow paints one or more shadows for a box—outside (drop) or inside (inset)—without extra markup or PNGs. Each shadow has offset, blur, spread, and color. Most polished UI shadows are layered: a soft wide layer plus a tighter darker one, sometimes with an inset highlight for “pressed” controls.

Anatomy of one shadow

The full form is:

box-shadow: inset? offset-x offset-y blur-radius? spread-radius? color?;
Part Role Typical values
inset (optional keyword) Shadow draws inside the padding edge omit for outer; add for wells / pressed
Offset X / Y How far the shadow shifts 0 4px (down), -2px 0 (left)
Blur Soft edge; 0 is a hard silhouette 8px24px for cards
Spread Grow (positive) or shrink (negative) before blur 0, 2px, or -4px
Color Usually semi-transparent black or brand rgb(0 0 0 / 0.15), #00000026

Omitted blur and spread default to 0. Color defaults to the element’s color (currentColor)—so always set an explicit color for predictable UI tokens.

/* Single outer shadow */
box-shadow: 0 8px 24px rgb(0 0 0 / 0.12);

/* Inset (inner) shadow */
box-shadow: inset 0 2px 4px rgb(0 0 0 / 0.2);

Offset, blur, and spread in practice

Offset places the shadow relative to the box. Positive Y reads as light from above (shadow falls down)—the usual card lift. Large X/Y with little blur looks like a second copy of the box; keep offsets modest unless you want that effect.

Blur is the soft radius. Doubling blur without changing opacity often looks “floatier” but washed out—pair larger blur with slightly lower opacity, or stack a second tighter layer so the silhouette stays readable.

Spread expands or contracts the shadow before blur. Positive spread makes a thicker halo (good for soft glows). Negative spread pulls the shadow inward so blur does not spill past the box as much—useful when a card sits near edges or other cards and you do not want muddy overlap.

Mental model:

  1. Take the box’s border box (or inset edge).
  2. Apply spread (grow/shrink).
  3. Apply blur.
  4. Shift by offset X/Y and paint with the color (respecting stacking and border-radius).

Shadows follow the element’s border-radius; a pill or squircle casts a matching soft edge. Pair radius work with a live preview when corners matter—see related CSS generators on LocalTools when you tune both.

Layering: why one shadow is rarely enough

Browsers accept a comma-separated list. Shadows are painted from first listed = topmost among the shadows (still behind the box’s background/border as a group). Design systems often stack two or three outer layers:

.card {
  box-shadow:
    0 1px 2px rgb(0 0 0 / 0.06),
    0 8px 24px rgb(0 0 0 / 0.08);
}
Pattern Layers Use
Soft card Small tight + larger soft Elevation without a hard rim
Brand glow Soft tinted outer (± slight inset) Focus rings, selected tiles
Pressed / inset One or two inset layers Inputs, toggles, recessed panels
Neumorphic-ish Light inset + dark inset (or outer pair) Skeuomorphic panels—easy to overdo

Mixing outer and inset in one declaration is valid:

.panel {
  box-shadow:
    0 4px 16px rgb(0 0 0 / 0.1),
    inset 0 1px 0 rgb(255 255 255 / 0.4);
}

The outer lift and the top highlight read as depth on light surfaces. On dark themes, flip the idea: lighter outer glow, darker inset—and check that text still meets contrast on the face of the control (WCAG contrast ratios).

Color and opacity

Pure #000 at full opacity looks harsh. Prefer alpha so the background shows through:

  • Neutral elevation: black or near-black at 6%–20% opacity.
  • Colored glow: brand HEX/HSL/OKLCH with alpha—convert and preview formats in the Color Converter if your tokens use different notations (HEX, RGB, HSL, and OKLCH).
  • Dark mode: grey or white with low alpha often beats black on near-black surfaces.

Opacity is part of the color, not a separate box-shadow parameter. Changing only blur while keeping the same alpha can make the shadow look stronger or weaker because more pixels are covered softly.

Pitfalls and tips

  • Performance. Huge blur radii and many layers on large or frequently animated elements cost more to paint. Prefer modest stacks; animate opacity or a CSS variable that scales offsets rather than thrashing giant blurs every frame.
  • filter: drop-shadow() follows the alpha shape of the element (good for irregular PNGs/SVGs). box-shadow follows the CSS box. Do not confuse them when debugging “why doesn’t my icon cast a shadow?”
  • Spread ≠ blur. Spread changes size; blur changes softness. Fixing “too big” with only blur often muddies edges—nudge spread or opacity instead.
  • Inset and overflow. Inset shadows clip to the padding box; overflow: hidden on ancestors can also clip outer shadows.
  • Focus visibility. A decorative glow is not a substitute for a visible :focus-visible outline that passes non-text contrast.
  • Tokens. Store full box-shadow strings (or layered custom properties) so light/dark themes can swap stacks without hunting magic numbers.

Why tune shadows locally

Brand colors, elevation tokens, and inset recipes are easy to paste into online generators. A client-side builder keeps those values in your tab—same privacy habit as other LocalTools utilities (Why “local only” matters for developer tools).

Try it on LocalTools

Open the CSS box-shadow generator:

  1. Start from a preset (soft, medium, large, indigo glow, or inset) or the default layer.
  2. Tune offset X/Y, blur, spread, color, and opacity; toggle inset per layer.
  3. Add layers for stacked elevation; switch the preview surface (light, dark, checker) to judge contrast.
  4. Copy the full box-shadow declaration into your CSS or design tokens.

Nothing is uploaded; the CSS updates as you edit.

Related reading

All learn articles