Skip to content
Free Tool Arena

Design & Media · Guide · Developer Utilities

How to use box shadows effectively

Box-shadow values decoded, Material-style elevation, multi-layer shadows, color and hue tinting, filter drop-shadow, dark mode, performance.

Updated April 2026 · 6 min read

Box shadow is the depth system of the web. Done right, it makes cards feel layered, buttons feel clickable, modals feel like they’re floating. Done wrong, it makes your page look like a 2010 iOS skeuomorphism tribute. This guide covers the six box-shadow values and what they actually do, the elevation system used by Material Design and modern design systems, inset shadows, multi-layer shadows that feel real, dark mode differences, performance, and the common mistakes that make shadows look bolted on.

Advertisement

The six values, decoded

box-shadow: offset-x offset-y blur spread color [inset]

offset-x: horizontal distance. Positive = right, negative = left.

offset-y: vertical distance. Positive = down, negative = up. Most shadows have positive y (light from above).

blur: how soft the shadow edge is. Higher = softer, larger apparent shadow. 0 = hard edge.

spread: how far the shadow grows or shrinks before the blur applies. Positive expands; negative contracts. Often omitted (defaults to 0).

color: shadow color, usually semi-transparent black or dark.

inset: optional keyword — shadow appears inside the element instead of outside.

The elevation model

Material Design popularized a tiered shadow system where each level represents how “lifted” an element is. Modern design systems (Tailwind, Radix Themes, Chakra) follow the same pattern.

Elevation 1 (xs): subtle separation — 0 1px 2px rgba(0,0,0,0.05). For borderless cards or input fields.

Elevation 2 (sm): cards, buttons — 0 1px 3px rgba(0,0,0,0.1).

Elevation 3 (md): floating cards, dropdowns — 0 4px 6px rgba(0,0,0,0.1).

Elevation 4 (lg): hover states, popovers — 0 10px 15px rgba(0,0,0,0.1).

Elevation 5 (xl): modals, drawers — 0 20px 25px rgba(0,0,0,0.15).

Elevation 6 (2xl): big floating elements — 0 25px 50px rgba(0,0,0,0.25).

Use a consistent set across your project. Inconsistent shadows are the tell of a hand-built design.

Multi-layer shadows — the secret to realism

Real-world shadows have multiple components: the hard “contact” shadow right under the object and the soft ambient shadow further away. A single CSS shadow approximates one of these; stacking two makes the object feel grounded.

box-shadow: 0 1px 2px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.04);

The first layer is tight and sharper (contact); the second is diffuse (ambient). Multi-layer shadows are what make Stripe and Linear UIs look polished.

Tailwind’s default shadow-md: four layered rgba shadows. Look at the computed value — it’s a stack, not a single shadow.

Color — black isn’t always right

Pure black (#000) shadows look dirty against colored backgrounds. Instead:

Match the shadow hue to the background: on a blue card, tint the shadow blue-black. rgba(30, 50, 100, 0.15) instead of rgba(0,0,0,0.15).

Use the element’s color at low opacity:for a purple button, box-shadow: 0 4px 14px 0 rgba(128, 0, 255, 0.39) feels like the button is glowing instead of casting a shadow.

Dark mode: shadows on dark backgrounds are nearly invisible. Switch to highlight-based elevation (subtle inner glow, lighter border, or increased brightness) or use much darker, larger shadows (rgba(0,0,0,0.6)).

Inset shadows

inset inverts the shadow — it appears inside the element, useful for depressed states (a pressed button) or neumorphic designs.

box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);

Classic use: input fields in older UIs, pressed-button states, card thumbnails with subtle inner border.

Can combine inset and outset in one rule: box-shadow: inset 0 1px 0 rgba(255,255,255,0.1), 0 1px 2px rgba(0,0,0,0.2); creates a glossy highlight at top with a cast shadow below.

Filter drop-shadow — for complex shapes

box-shadow draws the shadow from the element’s rectangular border box. If you have a PNG with transparency or an SVG icon, the shadow will be rectangular, not following the shape.

Solution: use filter: drop-shadow(...). It follows alpha channels.

filter: drop-shadow(0 4px 6px rgba(0,0,0,0.3));

Slightly more expensive to render than box-shadow (GPU filter pass vs layout-only). Use for icons and irregular shapes, box-shadow for rectangles.

Hover and transition

A classic move: slight shadow increase on hover to suggest the element is lifting.

.card { box-shadow: 0 2px 4px rgba(0,0,0,0.1); transition: box-shadow 0.2s ease, transform 0.2s ease; } .card:hover{ box-shadow: 0 8px 16px rgba(0,0,0,0.15); transform: translateY(-2px); }

The translateY reinforces the lift; the larger shadow reads as distance from the surface.

Keep transitions short. 150-250ms feels responsive; longer feels laggy.

Performance considerations

Shadows are GPU-accelerated but expensive compared to flat-color rendering.

Large blur radius on large elements is the most expensive case — the GPU has to composite a huge transparent area. Limit blur to what you actually need.

Many layered shadows × many elements can cause jank during scroll on low-end devices. If you have 50 cards each with 4-layer shadows, profile scroll performance.

Animating box-shadow triggers repaint on every frame. Prefer animating transform and opacity instead. If you need the shadow change, consider using a pseudo-element with opacity toggles.

Dark mode — the full redesign

Shadows don’t read on dark backgrounds. Alternatives:

Lighter border as elevation. Dark surfaces get a 1px lighter top border (border-top: 1px solid rgba(255,255,255,0.1)).

Background lightness change. Each elevation level = slightly lighter surface (instead of shadow). Material Design’s dark theme uses this.

Colored glow. Brand-colored shadow at low opacity can still register on dark backgrounds.

Strong shadow. rgba(0,0,0,0.6) or higher, with substantial blur. Works best when there’s actual contrast under the element.

Common mistakes

Full-black shadows on colored backgrounds.Reads as dirty. Tint the shadow.

Single-layer shadow on a flat design. Pairs a flat aesthetic with a sharp unrealistic shadow. Use multiple layers or no shadow at all.

Shadows on everything. Shadows are contrast cues — when everything has one, nothing stands out.

Identical shadow at every elevation. Usingshadow-md for cards, dropdowns, modals, and hero images flattens the hierarchy. Match shadow to semantic elevation.

Forgetting border-radius interaction. Hard corners with soft shadows look awkward. The shadow reads the element’s border-radius; make sure they agree visually.

Run the numbers

Tune shadows live with the box shadow generator. Pair with the border radius generator to match corner softness to shadow softness, and the gradient generator when layering shadows with background depth.

Advertisement

Found this useful?Email