← Blog
Web DesignApril 29, 20259 min

CSS Box Shadow: A Complete Guide with Examples

Master every parameter of box-shadow, layer multiple shadows for depth, and understand elevation design systems.

Syntax Breakdown

box-shadow: [inset] offset-x offset-y [blur-radius] [spread-radius] color;

/* Example */
box-shadow: 4px 8px 16px 0px rgba(0, 0, 0, 0.15);
  • offset-x: Horizontal shift. Positive moves right, negative moves left.
  • offset-y: Vertical shift. Positive moves down, negative moves up.
  • blur-radius: How blurry the shadow edges are. 0 = hard edge. Required to be ≥ 0.
  • spread-radius: Expands (+) or contracts (−) the shadow before blurring. Optional, defaults to 0.
  • color: The shadow color. Use rgba() for transparency.
  • inset: Makes the shadow render inside the element rather than outside.

Blur vs Spread

Blur and spread are often confused. Blur softens the edges — higher values create a more diffuse, atmospheric shadow. Spread changes the size of the shadow shape before blurring — a positive spread makes the shadow larger than the element; a negative spread makes it smaller.

/* Same offset and color, different blur and spread */
box-shadow: 0 4px 0px 0px #000;   /* hard shadow, no blur */
box-shadow: 0 4px 8px 0px #000;   /* soft shadow */
box-shadow: 0 4px 8px 4px #000;   /* soft shadow, expanded */
box-shadow: 0 4px 8px -4px #000;  /* soft shadow, contracted */

Multiple Shadows

You can layer multiple shadows with a comma-separated list. They render front-to-back — the first shadow is on top.

Layered shadow for depth

box-shadow:
  0 1px 2px rgba(0,0,0,0.04),
  0 4px 8px rgba(0,0,0,0.08),
  0 16px 32px rgba(0,0,0,0.06);

This technique produces a more natural shadow that tapers off with distance, simulating real light behavior.

Inset Shadows

The inset keyword makes the shadow appear inside the element, creating a pressed or recessed effect.

/* Pressed button effect */
.button:active {
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.2);
}

/* Neumorphic well */
.input {
  box-shadow:
    inset 3px 3px 6px #d1d1d1,
    inset -3px -3px 6px #ffffff;
}

Elevation Systems (Material Design Pattern)

Material Design defines a set of elevation levels, each with a specific shadow. This creates a consistent visual hierarchy across components:

:root {
  --shadow-1: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
  --shadow-2: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
  --shadow-3: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);
  --shadow-4: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
}

Performance Considerations

Box shadows trigger paint (not just composite) when they change during animation. To animate shadows smoothly:

  • Animate opacity of a pseudo-element with a shadow instead of the shadow itself
  • Or use filter: drop-shadow() which is hardware-accelerated via composite
  • Avoid animating spread-radius — it is especially expensive to repaint
/* Performant shadow animation using opacity */
.card::after {
  content: '';
  position: absolute; inset: 0;
  box-shadow: 0 20px 40px rgba(0,0,0,0.3);
  opacity: 0;
  transition: opacity 0.2s ease;
}
.card:hover::after { opacity: 1; }

Common Mistakes

  • Using pure black: rgba(0,0,0,0.15) looks more natural than #000000 with opacity
  • Too many shadows: More than 3 layers rarely adds visible benefit and increases paint cost
  • Ignoring dark mode: Dark-mode designs typically replace box shadows with subtle borders — shadows disappear on dark backgrounds

Try it yourself

Build CSS box shadows visually with live sliders and copy the generated code instantly.

Open Box Shadow Generator →