CSS box-shadow is one of those properties that looks simple on the surface but has surprising depth. This guide covers everything from the basics to multi-layer shadows, inset shadows, and performance considerations — with ready-to-copy examples throughout.
The Syntax
box-shadow: [offset-x] [offset-y] [blur-radius] [spread-radius] [color];
Each value:
- offset-x — horizontal shift (positive = right, negative = left)
- offset-y — vertical shift (positive = down, negative = up)
- blur-radius — higher = softer/larger shadow (can't be negative)
- spread-radius — expands or contracts the shadow before blur
-
color — any valid CSS colour, including
rgba()for transparency
Two values are the minimum required: offset-x and offset-y.
/* Minimal shadow */
box-shadow: 4px 4px black;
/* Typical card shadow */
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
Common Shadow Patterns
Soft / Subtle
Best for cards and containers where you want depth without drama.
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
Raised / Button
Makes an element look clickable — like a physical button.
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06);
Floating / Elevated
For modals, dropdowns, or any element that should appear above the page.
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15), 0 4px 10px rgba(0, 0, 0, 0.1);
Deep / Strong
Dramatic elevation — use sparingly.
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3), 0 6px 20px rgba(0, 0, 0, 0.2);
Inset Shadow
Renders the shadow inside the element, giving a pressed or sunken look.
box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.15);
Useful for input fields, toggle wells, or pressed button states.
Multi-Layer Shadows
You can stack multiple shadows by comma-separating them. They render front-to-back (first value is on top).
/* Two-layer shadow: tight dark + wide light */
box-shadow:
0 2px 4px rgba(0, 0, 0, 0.2),
0 8px 24px rgba(0, 0, 0, 0.1);
Multi-layer shadows look more natural than a single shadow because real-world light creates both a sharp contact shadow near the object and a soft diffuse shadow further away.
Spread Radius in Practice
The spread radius is often misunderstood. Positive spread expands the shadow before blur is applied; negative shrinks it.
/* Outline effect (0 blur, spread only) */
box-shadow: 0 0 0 3px #3b82f6;
/* Negative spread + large offset = shadow only at bottom */
box-shadow: 0 8px 10px -5px rgba(0, 0, 0, 0.3);
The 0 0 0 Xpx color pattern is a useful trick for adding a coloured ring/outline to any element — including images — without affecting layout (unlike outline, which can be clipped).
Colour and Opacity
Avoid hardcoded black shadows. Use rgba() with low alpha for realistic depth:
/* Too harsh */
box-shadow: 0 4px 8px black;
/* Natural */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
For coloured glow effects (useful for interactive elements):
/* Green glow */
box-shadow: 0 0 12px rgba(34, 197, 94, 0.5);
/* Blue focus ring */
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.4);
Transition and Animation
box-shadow is animatable. Combine with :hover or :focus transitions for responsive depth:
.card {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
transition: box-shadow 0.2s ease;
}
.card:hover {
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}
Keep transitions under 300ms. Longer delays feel sluggish.
Performance Notes
box-shadow triggers the browser's composite layer — it is painted, not composited. This means:
- Animating
box-shadowis more expensive than animatingtransformoropacity - For animation-heavy UIs, use a pseudo-element with
opacitytransition as a workaround:
.card::after {
content: '';
position: absolute;
inset: 0;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
opacity: 0;
transition: opacity 0.2s ease;
}
.card:hover::after {
opacity: 1;
}
This way you animate opacity (GPU-composited) instead of box-shadow directly.
Dark Mode Shadows
Box shadows over dark backgrounds often disappear or look harsh. Options:
-
Use
rgba()white shadows for a subtle emboss/lift effect - Reduce shadow opacity — a 0.5 alpha shadow that works on light needs ~0.15 on dark
- Add a border instead — often cleaner on dark UIs
@media (prefers-color-scheme: dark) {
.card {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.08);
}
}
Quick Reference
| Pattern | CSS |
|---|---|
| Soft card | 0 1px 3px rgba(0,0,0,0.1) |
| Raised button | 0 4px 6px rgba(0,0,0,0.1) |
| Floating modal | 0 10px 25px rgba(0,0,0,0.15) |
| Inset (pressed) | inset 0 2px 4px rgba(0,0,0,0.1) |
| Focus ring | 0 0 0 3px rgba(59,130,246,0.4) |
| Coloured glow | 0 0 12px rgba(34,197,94,0.5) |
Try It Live
Rather than tweaking values by hand, use a visual box shadow generator to dial in the exact look you want. SnappyTools CSS Box Shadow Generator lets you add up to 4 independent shadow layers with live preview, export as CSS, and start from one of 5 presets — all in the browser with no signup required.
Box shadows are one of the easiest ways to add depth and polish to a UI. Master the multi-layer approach and the rgba() opacity technique, and you'll stop reaching for border hacks to create the same effect.
Top comments (0)