Blog/CSS Box Shadow: A Complete Guide with Examples (2026)
CSS

CSS Box Shadow: A Complete Guide with Examples (2026)

Vikas Sharma

Vikas Sharma

Senior Frontend Developer

June 24, 2026•10 min read
CSS box-shadow examples showing layered shadows, inset shadows and elevation depth

box-shadow is one of the first CSS properties everyone learns and one of the last they actually master. The syntax looks simple, four numbers and a color, but the difference between a shadow that looks cheap and one that looks like it belongs in a design system comes down to understanding what each value really does and how to layer them. This guide takes you from the four values to production-grade elevation.

The anatomy of box-shadow

A single box-shadow takes up to five parts in this order: offset-x, offset-y, blur-radius, spread-radius, and color. Only the two offsets and a color are required, but you almost always want the blur too.

css
.box {
  /*           x    y    blur  spread  color */
  box-shadow:  0    4px  12px  0       rgba(0, 0, 0, 0.15);
}
  • offset-x - horizontal distance; positive pushes the shadow right, negative pushes it left
  • offset-y - vertical distance; positive pushes the shadow down (the common case), negative pushes it up
  • blur-radius - how soft the edge is; 0 is a hard-edged shadow, larger values feather it out. Cannot be negative
  • spread-radius - grows (positive) or shrinks (negative) the shadow before the blur is applied
  • color - use rgba or hsla with an alpha channel so the shadow tints rather than blocks the background

Why your shadows look fake

The most common mistake is a pure black shadow at high opacity: box-shadow: 0 5px 5px black. Real shadows are never solid black and never that harsh. Light scatters, so shadows are soft, low-contrast, and tinted by their surroundings. Two fixes make an instant difference.

  • Drop the opacity hard - rgba(0, 0, 0, 0.1) to 0.2 is plenty for most UI elements
  • Offset down, not sideways - light usually comes from above, so a shadow with a vertical offset and zero horizontal offset reads as natural

Compare 0 1px 2px rgba(0,0,0,0.1) against 2px 2px 4px black. The first looks like a real card resting on paper. The second looks like a 2008 web template.

Layering shadows for realistic depth

This is the single technique that separates professional shadows from default ones. box-shadow accepts a comma-separated list, and stacking two or three shadows mimics how real light works: a tight, dark shadow close to the object plus a wider, softer shadow further out.

css
.card {
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.08),
    0 4px 8px rgba(0, 0, 0, 0.08),
    0 16px 24px rgba(0, 0, 0, 0.08);
}

Each layer adds a different falloff. The result is a shadow with a believable gradient from sharp near the edge to diffuse far away, exactly what a physical object casts. This layered approach is what every major design system, Material, Apple HIG, Tailwind's shadow scale, uses under the hood.

Building an elevation system

Instead of inventing shadows per component, define a small scale of elevations and reuse them. Higher elevation means a larger, softer shadow, signaling the element is further from the page. Store them as custom properties:

css
:root {
  --elevation-1: 0 1px 2px rgba(0,0,0,0.08),
                 0 1px 3px rgba(0,0,0,0.1);
  --elevation-2: 0 4px 6px rgba(0,0,0,0.07),
                 0 2px 4px rgba(0,0,0,0.06);
  --elevation-3: 0 10px 20px rgba(0,0,0,0.08),
                 0 6px 6px rgba(0,0,0,0.1);
}

.card        { box-shadow: var(--elevation-1); }
.card:hover  { box-shadow: var(--elevation-3); }

Now hover states, modals, and dropdowns all pull from the same vocabulary, and your shadows feel like a coherent system instead of a pile of one-off values.

Inset shadows for inner depth

Add the inset keyword and the shadow renders inside the element instead of outside. This is how you create pressed buttons, input wells, and recessed panels. It is also the foundation of the neumorphism style.

css
.input-well {
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.12);
}

.button:active {
  box-shadow: inset 0 3px 6px rgba(0, 0, 0, 0.2);
}

Using an inset shadow on :active gives a button a tactile pressed feel, far more convincing than just shifting it down a pixel.

The spread value and its hidden uses

spread is the least understood value, but it has two genuinely useful tricks. A positive spread grows the shadow evenly, handy for glows. A negative spread shrinks it, which lets you create a shadow that only peeks out from one side for a subtle lifted-edge effect.

GoalDeclarationEffect
Soft glow0 0 0 4px rgba(59,130,246,0.4)Even ring around the element, great for focus states
Tight lifted edge0 8px 8px -4px rgba(0,0,0,0.2)Negative spread pulls the shadow in so it only shows below
Solid border substitute0 0 0 2px #1B4DFFCrisp ring with no blur, like a border that does not affect layout

That last row is a favorite: a zero-blur, zero-offset shadow with spread acts like a border that never shifts your box dimensions, perfect for focus rings and selected states.

Copy-paste examples

css
/* Subtle card */
.card { box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.08); }

/* Floating / modal */
.modal { box-shadow: 0 20px 40px rgba(0,0,0,0.2); }

/* Button hover lift */
.btn:hover { box-shadow: 0 6px 16px rgba(27,77,255,0.35); }

/* Accessible focus ring (no layout shift) */
.btn:focus-visible { box-shadow: 0 0 0 3px rgba(27,77,255,0.45); }

Performance note

Shadows are cheap to render statically but expensive to animate, because the browser repaints the blurred region every frame. Never animate box-shadow directly in a transition. Instead, layer a pseudo-element with the target shadow and animate its opacity, or animate transform for the lift and keep the shadow swap snappy. Your scroll and hover performance will thank you.

Hand-tuning offsets, blur, spread, and stacked layers gets fiddly fast. The CSS Box Shadow Generator gives you sliders for every value, supports multiple layered shadows and inset mode, and copies clean code instantly.

Conclusion

box-shadow rewards a little understanding enormously. Keep opacity low, offset shadows downward, layer two or three for realistic depth, codify them into an elevation scale, and reach for inset and spread when the situation calls for it. Master those and every card, button, and modal you build will look like it came from a polished design system, all from one humble property.

Table of Contents

Share Article

Vikas Sharma

Vikas Sharma

Senior Frontend Developer

Senior Frontend Developer with 8+ years of experience building production CSS layouts.