CSS Box-Shadow Table
| Component | What it does | Field note |
|---|---|---|
offset-x offset-y | 2px 4px | The only required pair - direction FROM the element, not toward the light |
blur-radius | Third length = softness | 0 = razor edge; blur extends BOTH directions from the offset |
spread-radius | Fourth length = growth | Positive inflates before blurring; negative shrinks - the ring trick |
inset | Shadow inside the box | The pressed-key / well look; pairs with an outset twin for depth |
color | rgba(0,0,0,.25) | NEVER pure black - 20-30% alpha black reads as depth, 100% reads as a sticker |
layered shadows | shadow, smaller shadow | Two shadows = soft + tight = the modern card look; one shadow reads flat |
negative spread ring | 0 0 0 3px color | Zero blur + positive spread = a solid ring - focus states without borders |
border-radius follows | Radius clips the shadow | box-shadow tracks the border-radius automatically - no extra work |
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
- 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.
- 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.
- 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.