CSS Box Shadow Explained: Syntax, Layering, and Practical Examples

The CSS box-shadow property adds shadow effects to elements. Here's how the syntax works, how to layer shadows for realistic depth, and what to avoid.

CSS Box Shadow Explained: Syntax, Layering, and Practical Examples

The CSS box-shadow property adds one or more shadow effects around an element's frame. It accepts values for horizontal offset, vertical offset, blur radius, spread radius, and color. You can stack multiple shadows in a single declaration and use the inset keyword for inner shadows.

This guide covers how each value works, how to combine shadows for realistic effects, common mistakes, and performance considerations.

Quick Reference

box-shadow: [inset] <offset-x> <offset-y> [<blur>] [<spread>] <color>;
Value What It Does Default
offset-x Horizontal position (positive = right) Required
offset-y Vertical position (positive = down) Required
blur Softness of the shadow edge 0 (sharp)
spread Expands or shrinks the shadow 0
color Shadow color (often with transparency) Varies by browser
inset Makes the shadow render inside the element Not set (outer)

How Each Value Works

Offset-X and Offset-Y

These control where the shadow appears relative to the element. Both values are required.

  • Positive offset-x moves the shadow right
  • Negative offset-x moves it left
  • Positive offset-y moves the shadow down
  • Negative offset-y moves it up
  • Both set to 0 centers the shadow directly behind the element (visible only if blur or spread is set)
/* Shadow 5px right and 10px below */
box-shadow: 5px 10px 0 0 rgba(0, 0, 0, 0.3);

/* Shadow 5px left and 3px above */
box-shadow: -5px -3px 0 0 rgba(0, 0, 0, 0.3);

Blur Radius

The blur radius controls how soft the shadow's edges are. Higher values produce a more diffused, spread-out shadow. A value of 0 creates a sharp-edged shadow.

Technically, the browser applies a Gaussian blur. The visible shadow extends beyond the shadow's box by the blur radius value.

/* Sharp shadow (no blur) */
box-shadow: 4px 4px 0 0 rgba(0, 0, 0, 0.3);

/* Soft shadow */
box-shadow: 4px 4px 15px 0 rgba(0, 0, 0, 0.2);

/* Very diffused shadow */
box-shadow: 4px 4px 40px 0 rgba(0, 0, 0, 0.1);

Spread Radius

Spread expands or contracts the shadow before blur is applied.

  • Positive spread makes the shadow larger than the element
  • Negative spread makes it smaller
  • Combined with zero offset and zero blur, spread creates a solid border-like effect
/* Shadow larger than the element */
box-shadow: 0 4px 10px 5px rgba(0, 0, 0, 0.15);

/* Shadow smaller than the element (useful for tight, realistic shadows) */
box-shadow: 0 10px 15px -5px rgba(0, 0, 0, 0.2);

/* Solid ring (no blur, no offset) */
box-shadow: 0 0 0 3px #3b82f6;

The solid ring technique is widely used for focus indicators and selection states because unlike border, it doesn't change the element's layout dimensions.

Color

Always specify a color explicitly. If omitted, browsers may use currentColor or black, and the behavior varies.

Use rgba() or hsla() for transparency:

/* Semi-transparent black — the most common shadow color */
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);

/* Colored glow */
box-shadow: 0 0 20px rgba(59, 130, 246, 0.5);

The inset Keyword

Adding inset renders the shadow inside the element instead of outside. It reverses the visual effect: instead of the element appearing to float above the page, it appears recessed or pressed in.

/* Inner shadow — pressed-in effect */
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2);

/* Outer and inner shadow combined */
box-shadow: 
  0 4px 6px rgba(0, 0, 0, 0.1),
  inset 0 1px 2px rgba(0, 0, 0, 0.06);

Layering Multiple Shadows

Separate multiple shadows with commas. The first shadow in the list renders on top (closest to the viewer).

Why Layer Shadows?

Real-world lighting produces multiple shadow effects simultaneously. A single box-shadow usually looks flat. Layered shadows simulate:

  1. Ambient light — soft, spread-out, low-opacity
  2. Direct light — tighter, more defined, slightly higher opacity

Layered Shadow Examples

Subtle card elevation (similar to Material Design elevation 2):

box-shadow: 
  0 1px 3px rgba(0, 0, 0, 0.12),
  0 1px 2px rgba(0, 0, 0, 0.24);

Medium elevation:

box-shadow:
  0 4px 6px -1px rgba(0, 0, 0, 0.1),
  0 2px 4px -2px rgba(0, 0, 0, 0.1);

High elevation (floating modal or dropdown):

box-shadow:
  0 20px 25px -5px rgba(0, 0, 0, 0.1),
  0 8px 10px -6px rgba(0, 0, 0, 0.1);

Dramatic depth (hero section or featured card):

box-shadow:
  0 25px 50px -12px rgba(0, 0, 0, 0.25);

The pattern: use negative spread to keep shadows tight, combine a large soft shadow with a smaller sharp one, and keep total opacity low.

Practical Patterns

Focus Ring Without Layout Shift

/* No layout shift — unlike border, box-shadow doesn't affect dimensions */
button:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.5);
}

Colored Glow Effect

.glow-blue {
  box-shadow: 0 0 15px rgba(59, 130, 246, 0.4);
}

.glow-green {
  box-shadow: 0 0 15px rgba(34, 197, 94, 0.4);
}

Neumorphism (Soft UI)

.neumorphic {
  background: #e0e5ec;
  box-shadow:
    8px 8px 16px #b8bec7,
    -8px -8px 16px #ffffff;
}

Bottom-Only Shadow

/* Negative spread clips the sides, offset pushes it down */
.bottom-shadow {
  box-shadow: 0 4px 6px -6px rgba(0, 0, 0, 0.3);
}

Text Input Highlight on Focus

input:focus {
  box-shadow: 0 0 0 2px #3b82f6, 0 0 8px rgba(59, 130, 246, 0.2);
}

Common Mistakes

Using Pure Black at High Opacity

Pure black (rgba(0, 0, 0, 0.5)) rarely looks natural. In real life, shadows pick up surrounding colors. Keep opacity below 0.25 for most cases, or use a dark version of the background color instead.

Shadows That Are Too Large or Too Sharp

Overly large offsets without sufficient blur look harsh. Overly blurred shadows without enough offset look like the element is glowing rather than elevated. Match shadow size to the visual "height" you want to convey.

Forgetting will-change for Animated Shadows

Animating box-shadow is expensive because the browser repaints on every frame. If you must animate shadows, use will-change: box-shadow or consider transitioning opacity on a pseudo-element with a fixed shadow instead.

Not Specifying Color

Omitting the color parameter produces inconsistent results across browsers. Always specify the color explicitly.

Performance Notes

  • box-shadow triggers paint operations but not layout or compositing
  • Avoid animating box-shadow directly on elements that change frequently
  • Large blur values (50px+) cost more to render, especially on older devices
  • For performance-critical animations, apply the shadow to a ::after pseudo-element and animate its opacity instead of changing the shadow values
/* Performance-friendly shadow animation */
.card {
  position: relative;
}

.card::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
  opacity: 0;
  transition: opacity 0.3s ease;
  pointer-events: none;
}

.card:hover::after {
  opacity: 1;
}

box-shadow vs filter: drop-shadow()

Feature box-shadow filter: drop-shadow()
Follows element shape No (always rectangular) Yes (follows alpha channel)
Supports inset Yes No
Supports spread Yes No
Multiple shadows Yes (comma-separated) Yes (chain filters)
Works on images with transparency No (shadow is box-shaped) Yes (shadow follows visible pixels)

Use box-shadow for cards, buttons, and containers. Use drop-shadow() when you need shadows that follow non-rectangular shapes, like icons or PNG images with transparency.

Browser Support

box-shadow is supported in all modern browsers, including Chrome, Firefox, Safari, Edge, and mobile browsers. No vendor prefixes are needed.

The property has been supported since:

  • Chrome 10+
  • Firefox 4+
  • Safari 5.1+
  • Edge 12+
  • iOS Safari 5+
  • Android Browser 4+

FAQ

What is the CSS box-shadow property?

The box-shadow property adds shadow effects to an element's frame. It accepts horizontal offset, vertical offset, optional blur radius, optional spread radius, and color. Multiple shadows can be stacked in one declaration.

How do I add multiple shadows to one element?

Separate each shadow with a comma. The first shadow renders on top. Example: box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);

What does the spread value do in box-shadow?

Spread expands (positive values) or contracts (negative values) the shadow before blur is applied. A spread of 5px makes the shadow 5px larger on all sides. A spread of -5px shrinks it.

How do I create an inner shadow in CSS?

Add the inset keyword before the offset values: box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2);. The shadow renders inside the element instead of outside.

Does box-shadow affect element size or layout?

No. Box shadows are purely visual and do not change the element's dimensions or affect document flow. This is why they're useful for focus indicators as an alternative to border.

Can I animate box-shadow with CSS transitions?

Yes, but it's expensive. Each frame triggers a repaint. For smoother animations, apply the shadow to a pseudo-element and transition its opacity instead.

What is the difference between box-shadow and drop-shadow?

box-shadow always creates a rectangular shadow matching the element's box. filter: drop-shadow() follows the element's actual visible shape, including transparent areas. drop-shadow() does not support inset or spread.

How do I make a shadow appear only on one side?

Use offset to push the shadow in one direction and negative spread to clip the other sides. For a bottom-only shadow: box-shadow: 0 4px 6px -6px rgba(0, 0, 0, 0.3);

Why does my box-shadow look different on dark and light backgrounds?

Shadow visibility depends on contrast with the background. On dark backgrounds, use lighter shadow colors or colored shadows. On light backgrounds, dark semi-transparent shadows work well. Adjust opacity to match.

What is the best box-shadow for cards?

A common pattern is two layered shadows: box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);. The combination of a soft ambient shadow and a tighter direct shadow creates realistic depth.

Can I use box-shadow to create a border that doesn't affect layout?

Yes. Use zero offset, zero blur, and a positive spread: box-shadow: 0 0 0 2px #3b82f6;. This creates a solid outline without changing the element's size.

How many box-shadow layers can I use?

There's no hard limit. Browsers handle dozens of layers, but each additional layer costs rendering performance. Two to four layers typically achieve realistic effects without significant cost.

Does box-shadow work with border-radius?

Yes. The shadow automatically follows the element's border-radius, creating rounded shadow edges for rounded elements.

What color should I use for shadows?

Use semi-transparent black for most cases: rgba(0, 0, 0, 0.1) to rgba(0, 0, 0, 0.25). Avoid high opacity. For colored surfaces, consider tinting the shadow with the background color for a more natural look.

Related Tools

Related Tools