Web & Design
CSS box-shadow Explained: Build Realistic Shadows Visually
Understand the CSS box-shadow syntax — offset, blur, spread and inset — then design and copy production-ready shadows with a live visual editor.
Try the toolBox Shadow Generator →Shadows make an interface feel physical — cards lift off the page, buttons look pressable, dropdowns float. But box-shadow has five separate values plus an optional keyword, and nudging them blindly in a stylesheet means an endless save-and-refresh loop. Seeing the shadow change as you drag a slider is far faster than guessing pixel values.
How the box-shadow syntax works
A single shadow is written as a list of values:
box-shadow: offset-x offset-y blur spread color;
- offset-x moves the shadow right (positive) or left (negative).
- offset-y moves it down (positive) or up (negative).
- blur softens the edge;
0is a hard shadow, larger values fade it out. - spread grows (positive) or shrinks (negative) the shadow before blurring. Negative spread is the secret to tight, subtle shadows.
- color is any CSS color. Using
rgba()with a low alpha keeps shadows soft rather than muddy black.
Add the inset keyword and the shadow is drawn inside the box instead of outside — perfect for pressed buttons and inset wells.
A practical walkthrough
The Box Shadow Generator gives you sliders for X and Y offset, blur, spread, and opacity, plus a color picker and an inset toggle. Everything renders on a live preview box and the CSS updates instantly. A pleasant elevated-card shadow lands around these values:
.card {
box-shadow: 0px 12px 32px -6px rgba(0, 0, 0, 0.24);
}
Notice the negative spread (-6px): it pulls the shadow in so only a soft pool shows beneath the card, rather than a heavy halo on every side.
Layering shadows for realism
Real objects cast more than one shadow: a crisp contact shadow right at the edge and a wider, softer ambient one. You can stack multiple shadows in a single property by separating them with commas — the first one sits on top:
.card {
box-shadow:
0 1px 2px rgba(0, 0, 0, 0.08),
0 8px 24px rgba(0, 0, 0, 0.12);
}
Design one layer at a time in the generator, then paste the values together into a comma-separated list for a far more convincing result than any single shadow gives.
Common pitfalls and tips
Pure black is too harsh. rgba(0,0,0,1) looks like a sticker. Drop the opacity to somewhere between 0.08 and 0.3 so the shadow tints the background instead of blotting it out.
box-shadow respects border-radius; it does not clip content. If you need the shadow to follow an irregular PNG or icon shape, reach for filter: drop-shadow() instead.
Mind performance on animations. Animating box-shadow directly can be janky. For hover lifts, animate transform and cross-fade to a pre-defined larger shadow, or animate the opacity of a pseudo-element that holds the shadow.
Keep a consistent elevation scale. Rather than inventing a new shadow per component, define two or three reusable levels (resting, hover, modal) and stick to them across the UI.
Subtle shadows read as expensive; heavy ones read as cheap. When in doubt, lower the opacity and reduce the offset.
Wrapping up
Once you understand offset, blur, spread, and inset, box-shadow stops being trial and error. Dial in each value visually, layer two shadows for depth, and copy the exact CSS. Pair your shadows with a matching backdrop from the CSS Gradient Generator, and grab shadow colors that fit your palette using the Color Picker. Everything runs in your browser, so you can iterate as much as you like.