The box-shadow property is one of the most powerful CSS properties for making UI elements feel real. A well-placed shadow turns a flat button into something you want to click. A subtle card shadow separates content from the background without a hard border. But getting it right from memory is genuinely hard — the syntax has five parameters, and composing multiple shadows mentally is nearly impossible.
This guide covers everything you need to know about CSS box shadows, from the syntax to layered shadows, common presets, and performance tips.
The Syntax
box-shadow: [inset] offset-x offset-y [blur-radius] [spread-radius] color;
Breaking down each part:
- offset-x — how far the shadow is pushed right (negative = left)
- offset-y — how far the shadow is pushed down (negative = up)
- blur-radius — how soft the shadow edge is (0 = sharp, higher = softer)
- spread-radius — how much bigger the shadow is than the element (negative = smaller)
-
color — use
rgba()for transparency control - inset — optional keyword that puts the shadow inside the element
Five Presets Worth Memorising
These cover 90% of UI use cases.
Soft — subtle depth for cards:
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
Raised — button that looks clickable:
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.12), 0 1px 3px rgba(0, 0, 0, 0.08);
Floating — modal or dropdown:
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.18), 0 4px 12px rgba(0, 0, 0, 0.1);
Deep — primary CTA button:
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.24);
Inset — pressed state or sunken input:
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15);
Layered Shadows
You can stack multiple shadows by separating them with commas. This is how you get the natural-looking light falloff that real objects have — a sharp inner shadow for the contact shadow and a diffused outer shadow for the ambient light:
box-shadow:
0 1px 2px rgba(0, 0, 0, 0.20),
0 4px 8px rgba(0, 0, 0, 0.12),
0 16px 32px rgba(0, 0, 0, 0.06);
The first shadow is the sharpest and darkest (close contact). Each subsequent shadow is softer and more transparent (further from the surface). This technique is directly inspired by how actual light works.
Colour-Tinted Shadows
Pure black shadows (rgba(0,0,0,...)) can look synthetic. For a more organic result, tint the shadow toward the element's colour or your page's dominant hue:
/* Green-tinted shadow for a success button */
.btn-success {
background: #2f855a;
box-shadow: 0 4px 12px rgba(47, 133, 90, 0.4);
}
This creates a glow effect that feels cohesive rather than pasted on.
Spread Radius: Inset Borders and Glow Effects
The spread radius is underused. At positive values, it creates a glow or ring effect:
/* Focus ring that doesn't shift layout */
:focus-visible {
box-shadow: 0 0 0 3px rgba(47, 133, 90, 0.5);
}
This is far better than outline for styling — it follows border-radius, and outline-offset is tricky to control. Using box-shadow for focus rings is a design system staple.
At negative values, the spread radius makes the shadow smaller than the element — useful for creating the illusion that a shadow only falls below the bottom edge:
box-shadow: 0 4px 6px -2px rgba(0, 0, 0, 0.2);
Performance: When to Use will-change
Animating box-shadow is expensive — the browser repaints on every frame. If you animate shadows on hover or during scroll, move the shadow to a ::after pseudo-element and animate opacity instead:
.card {
position: relative;
}
.card::after {
content: '';
position: absolute;
inset: 0;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.18);
opacity: 0;
transition: opacity 0.2s ease;
pointer-events: none;
}
.card:hover::after {
opacity: 1;
}
opacity composites on the GPU — no repaint. This gives you silky 60fps shadow transitions even on low-end devices.
Dark Mode Shadows
In dark mode, dark shadows on a dark background are invisible. Switch to subtle light or coloured shadows instead:
@media (prefers-color-scheme: dark) {
.card {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.6);
/* Or use a border instead */
border: 1px solid rgba(255, 255, 255, 0.08);
}
}
The common dark mode pattern is to replace heavy shadows with a combination of slightly lighter backgrounds and hairline borders — shadows in dark themes often do more harm than good.
Tools Worth Bookmarking
Generating complex layered shadows by hand is tedious. If you're working with CSS design tools, a few free browser-based tools can save you significant time:
- CSS Gradient Generator — create linear, radial, and conic gradients with a visual editor and copy the CSS instantly
- Color Picker — pick any colour and copy it in hex, RGB, or HSL — useful when choosing shadow tint colours
- Color Contrast Checker — verify WCAG AA/AAA compliance between your shadow-affected text and background
These are all free, run in the browser with no data uploaded, and no signup required.
The One Rule
The most common mistake with box shadows: too many, too dark, too spread. If you can see your shadow clearly from three feet away, it's too strong. Shadows should create depth, not compete for attention. When in doubt, halve the opacity and see if the depth is still there. Usually it is.
Happy building.
Top comments (0)