CSS Box-Shadow Table

ComponentWhat it doesField note
offset-x offset-y2px 4pxThe only required pair - direction FROM the element, not toward the light
blur-radiusThird length = softness0 = razor edge; blur extends BOTH directions from the offset
spread-radiusFourth length = growthPositive inflates before blurring; negative shrinks - the ring trick
insetShadow inside the boxThe pressed-key / well look; pairs with an outset twin for depth
colorrgba(0,0,0,.25)NEVER pure black - 20-30% alpha black reads as depth, 100% reads as a sticker
layered shadowsshadow, smaller shadowTwo shadows = soft + tight = the modern card look; one shadow reads flat
negative spread ring0 0 0 3px colorZero blur + positive spread = a solid ring - focus states without borders
border-radius followsRadius clips the shadowbox-shadow tracks the border-radius automatically - no extra work
Reference: the MDN box-shadow reference. Shadow syntax is four decisions in order: WHERE (offsets), how SOFT (blur), how BIG (spread), how DARK (color with alpha). The design mistake to avoid: full-opacity black shadows read as stickers; the material look is 20-30% alpha black, layered - a wide soft shadow plus a tight close one is the modern card. Bottom line: zero-blur with positive spread makes solid rings (focus states without borders), inset gives the pressed look, and the shadow automatically follows border-radius - offset direction is FROM the element, which is why the sun is behind you. Related tools: filter table (drop-shadow traces alpha shapes instead), backgrounds table (the boxes shadows measure against), and animations table (transitioning shadow layers cheaply).

Box-shadow syntax is four decisions in order: WHERE the shadow falls (offset-x offset-y), how SOFT it is (blur-radius), how BIG before softening (spread-radius), and how DARK it reads (color with alpha). inset flips the whole thing inside the box for the pressed-key look.

Bottom line: never pure black. The material depth look is 20-30% alpha black, LAYERED - a wide soft shadow plus a tight close one is the modern card, and a single shadow reads flat. Zero blur with positive spread is the sleeper trick: 0 0 0 3px makes a solid ring, the focus-state treatment that survives border-radius.

The honest part: box-shadow only draws rectangles matching the border box. When the shape itself must cast - a transparent PNG star, an SVG blob - that is drop-shadow()'s job, the filter that reads the rendered alpha instead of the geometry.

How to use

  1. Build the standard card: box-shadow: 0 1px 2px rgba(0,0,0,.08), 0 8px 24px rgba(0,0,0,.12) - tight contact plus wide ambient, the two-layer default.
  2. Make a focus ring without borders: box-shadow: 0 0 0 3px rgba(59,130,246,.5) on :focus-visible - zero blur, positive spread, rounded corners handled free.
  3. Press a key: inset 0 2px 4px rgba(0,0,0,.2) on :active - inner shadow reads as depth below the surface, the physical button metaphor.

Frequently asked questions

Why do my shadows look cheap and heavy?

Almost always color opacity, not geometry. Full-opacity black (#000) at any blur reads as a sticker outline; real-world shadows are 20-30% alpha black - light that never fully blocks. The second culprit is a single shadow doing all the work: physical objects cast a tight contact shadow where they touch plus a wide ambient shadow that fades with distance, so the layered pair (0 1px 2px + 0 8px 24px) is what makes a card float. One layer, one blur = the 2013 flat-design look.

What does spread-radius actually do, and when is it useful?

Spread inflates or deflates the shadow BEFORE blur is applied: positive grows it in every direction, negative shrinks it. Zero blur plus positive spread therefore draws a SOLID shape - the ring trick (0 0 0 3px) behind focus states, badges and selected borders, with the box's border-radius respected automatically. Negative spread with large blur is the other end: it pulls the shadow under the element so only a soft halo peeks out - the grounded look for elements sitting on surfaces.

When is box-shadow the wrong tool versus drop-shadow?

When the element's visible shape is not its box. box-shadow computes from the border-box geometry - a transparent PNG logo, an SVG icon or a clipped shape gets a rectangular shadow that ignores the cutout. filter: drop-shadow() runs after rendering, reads the actual alpha channel, and traces the silhouette - star-shaped logo, star-shaped shadow. The trade: drop-shadow costs more per frame and lacks spread, so box-shadow stays the default for cards and panels, and drop-shadow is the escalation for shapes that are not rectangles.

Do box-shadows affect layout or accessibility?

Neither - which is exactly why they are safe to layer. Shadows paint outside the box without triggering overflow, layout shift or scrollbars, and screen readers ignore them entirely; elevation is purely visual signaling. Two real cautions: heavy shadow layering on huge blurred areas costs GPU compositing on low-end devices (keep blur radii sane on mobile-first elements), and shadow-alone elevation fails low-vision users who filter out subtle contrast - pair the depth cue with a border or background change for state.

Related tools