Box shadow generator
Stack layers, adjust them visually, and copy the CSS. Convincing shadows need two or three soft layers rather than one hard one.
The four numbers
| Value | Does what | Usually |
|---|---|---|
| X offset | Moves the shadow left or right | 0 — light comes from above, not the side |
| Y offset | Moves it down | Positive, and roughly half the blur |
| Blur | How soft the edge is | The largest of the four |
| Spread | Grows or shrinks the shadow before blurring | 0, or negative to pull it in |
Negative spread is the least-used and most useful of the four. It shrinks the shadow so it does not spill out sideways, which is what stops a large blur looking like a halo.
Why one layer never looks right
A real object casts a small, dark, tight shadow where it meets the surface, and a large, faint, diffuse one further out. A single CSS shadow can only be one of those, which is why single-layer shadows look like stickers.
Two layers is the minimum for something convincing. The default above is the pattern most design systems converge on:
.card {
box-shadow:
0 1px 2px rgba(16, 27, 45, 0.06),
0 8px 28px -18px rgba(16, 27, 45, 0.35);
}
The first layer is the contact shadow: barely offset, barely blurred, very subtle. The second is the ambient one: pushed down, heavily blurred, pulled in with negative spread so it stays under the card instead of leaking around it.
Keep the light source consistent
Every shadow on a page should behave as though one light is above it. That means X offset stays at 0 and Y offset stays positive, everywhere, without exception.
What changes between elements is elevation, not direction. A card sitting almost flat gets a small offset and a small blur. A modal floating above everything gets a large offset and a large blur. Define three or four levels, name them, and use only those:
--shadow-1: 0 1px 2px rgba(16,27,45,.06);
--shadow-2: 0 2px 4px rgba(16,27,45,.06), 0 8px 24px -16px rgba(16,27,45,.3);
--shadow-3: 0 4px 8px rgba(16,27,45,.08), 0 16px 40px -20px rgba(16,27,45,.4);
Ad-hoc shadows are what make an interface feel unplanned. A scale makes depth mean something.
Inset shadows
Add inset and the shadow falls inside the element instead of outside. Three genuine uses:
- Pressed states. A small inset shadow on
:activemakes a button feel like it goes in. - Input fields. A faint inset shadow at the top reads as recessed, which is the conventional signal for "you can type here".
- Hairline borders that do not affect layout.
inset 0 0 0 1pxdraws a one-pixel line inside the element without adding to its size the way a real border does.
Dark mode changes the rules
Shadows work by darkening what is behind them. On a dark background there is nothing left to darken, so a shadow that reads as crisp elevation in light mode disappears entirely in dark mode.
Two options. Make the shadows much stronger and much larger — near-black at high opacity, spread wide. Or stop using shadows for depth and use surface lightness instead: raise the background of the elevated element a step, which is how most dark interfaces actually signal layering.
Performance
Static shadows are cheap. Animated ones are not — box-shadow triggers a repaint on every
frame, and a large blur radius makes each of those repaints expensive.
For a hover lift, animate transform: translateY() instead, which is GPU-accelerated. If you
need the shadow itself to change, stack a pseudo-element with the stronger shadow and animate its
opacity — opacity is also GPU-accelerated, so the whole thing stays on the compositor.
.card {
transition: transform .18s ease;
box-shadow: 0 1px 2px rgba(16,27,45,.06), 0 8px 28px -18px rgba(16,27,45,.35);
}
.card:hover { transform: translateY(-2px); }
Questions about this generator
Why does my shadow look like a grey box?
Blur is too low for the offset, or opacity is too high. Try roughly doubling the blur relative to the Y offset and dropping the alpha below 0.2. Soft and faint reads as a shadow; hard and dark reads as a second element.
Should shadows be black?
Rarely. Pure black at low opacity turns everything under it grey. Tinting the shadow toward your background's hue — a deep navy on a cool interface, a warm brown on a cream one — looks noticeably more natural. The default above uses a dark navy for this reason.
What is the difference between box-shadow and drop-shadow?
box-shadow follows the element's box, so a transparent PNG gets a rectangular shadow. filter: drop-shadow() follows the actual shape, including transparency, which is what you want for logos and irregular SVG. It is more expensive to render and takes no spread value.
How many layers is too many?
Three or four is plenty for anything. Beyond that you are adding paint cost for a difference nobody can see. If a shadow is not landing, the fix is usually the ratio between blur and offset, not another layer.
Do shadows affect layout?
No. A shadow paints outside the element without occupying space, so it never pushes anything around — which also means it can be clipped by a parent with overflow: hidden. That is the usual reason a shadow mysteriously vanishes on one side.
Related tools
CSS Formatter
Lay out stylesheets with consistent indentation.
OpenCSS Minifier
Compress stylesheets for production.
OpenCSS Gradient Generator
Build linear, radial and conic gradients visually.
OpenMeta Tag Generator
Build a full head block with a live search and social preview.
OpenSchema Markup Generator
Produce valid JSON-LD for rich results.
Openrobots.txt Generator
Write crawl rules without guessing the syntax.
OpenLearn the why, not just the how
Longer reading on formatting, indentation and minification.