Build a box-shadow and watch the preview update as you drag. Stack several layers: two or three faint shadows read as depth, while one strong shadow looks like a sticker stuck on the page.
box-shadow: x y blur spread color. The offsets move
the shadow, blur softens its edge, and spread grows or shrinks
the shadow before the blur is applied.
Use negative spread to keep a shadow under the
card. A negative spread pulls the shadow in, so a
large y offset and blur stay below a wide card instead of
leaking out at the sides. For example, the Floating preset
uses 0 12px 32px -8px.
A single 0 4px 12px rgba(0,0,0,.2) reads as a
sticker on a page. Real objects cast more than one shadow: a
small tight one where they meet the surface, and a larger, much
fainter one further out. Most design-system depth scales are
built this way, and the Layered depth preset above stacks
three layers at 6%, 8% and 10% opacity.
Keep every layer under about 15% opacity. The layers add up where they overlap, so three layers at 8% look softer and more natural than one at 30%.
Unlike a border, a shadow is painted outside the box and never affects layout, so adding one does not move any other element.
Tick inset on a layer and the same numbers are drawn inside the element. Use it for pressed buttons and inputs.
Large blur radii take longer to paint, and animating box-shadow repaints every frame. Put the shadow on a pseudo-element and animate its opacity instead.
0 0 0 3px with a translucent brand color gives a focus ring that follows the border radius. The Focus glow preset does this. Browsers only made outline follow border-radius in the last few years.
:root {
/* Each level stacks a tight shadow with a wider, fainter one */
--shadow-sm: 0 1px 2px rgb(15 23 42 / 0.05);
--shadow: 0 1px 2px rgb(15 23 42 / 0.06),
0 4px 8px -2px rgb(15 23 42 / 0.08);
--shadow-lg: 0 1px 2px rgb(15 23 42 / 0.06),
0 4px 8px -2px rgb(15 23 42 / 0.08),
0 16px 32px -8px rgb(15 23 42 / 0.10);
}
.card { box-shadow: var(--shadow); }
.card:hover { box-shadow: var(--shadow-lg); }
/* Tinting toward the background rather than pure black keeps
the shadow from looking like dirt on a coloured surface. */ /* Slow: box-shadow repaints the element every frame */
.card { transition: box-shadow 200ms; }
/* Fast: the shadow lives on a pseudo-element and only its
opacity animates, which the compositor handles on the GPU */
.card { position: relative; box-shadow: var(--shadow); }
.card::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
box-shadow: var(--shadow-lg);
opacity: 0;
transition: opacity 200ms;
pointer-events: none;
}
.card:hover::after { opacity: 1; } /* box-shadow follows border-radius, which outline historically did not */
.button:focus-visible {
outline: none;
box-shadow: 0 0 0 3px rgb(99 102 241 / 0.45);
}
/* Modern browsers support outline-offset and rounded outlines,
so plain outline is fine again and does not affect layout at all.
Keep the shadow version only if you need the softer edge. */
.button:focus-visible {
outline: 2px solid #6366f1;
outline-offset: 2px;
} Use filter: drop-shadow() when the shape is not a rectangle. It follows the element's alpha channel, so it works on a PNG with transparency, an SVG icon or text, where box-shadow outlines the rectangle. However, it takes longer to render than box-shadow.
This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.
Horizontal offset, vertical offset, blur radius and spread. The offsets move the shadow, blur softens its edge, and spread grows or shrinks it before the blur is applied. Use a negative spread to keep a shadow tucked under a wide element, for example 0 12px 32px -8px.
Stack two or three layers. A small, tight shadow close to the element plus a larger, softer, fainter one reads as depth, while a single 20px blur reads as a sticker. Click Add layer for each one and keep every layer under about 15% opacity.
It draws the shadow inside the box instead of outside, so the element looks pressed in rather than raised. Use it for inputs and for toggle buttons in their active state. Tick inset on a layer, or start from the Pressed inset preset.
No. This is the main difference from a border: a shadow is painted outside the element's box and takes up no space, so adding one never moves anything around it.
Large blur radii take longer to paint, and animating box-shadow forces a repaint every frame. Put the shadow on a pseudo-element and animate its opacity instead, which the compositor can handle without repainting.
Rounded corners come from the border radius generator, and backgrounds from the gradient generator. To tidy the finished stylesheet, use the CSS formatter.