CSS Drop Shadow Tutorial: box-shadow vs filter: drop-shadow()

May 28, 20267 min read

Two Ways to Add Shadows

CSS offers two shadow mechanisms: box-shadow and filter: drop-shadow(). They look similar but behave differently in ways that directly affect your design. Picking the wrong one leads to rectangular shadows behind transparent pixels, clipped effects on irregular shapes, or confusing double-shadow artifacts.

Box Shadow vs. Drop Shadow

The core difference is shape. box-shadow follows the rectangular bounding box of an element. filter: drop-shadow() follows the visible alpha contour — the actual rendered pixels.

PropertyFollowsIgnoresBest For
box-shadowElement bounding boxAlpha transparencyCards, buttons, containers
drop-shadow()Visible alpha contourBounding box geometryPNG icons, clip-path shapes, SVG graphics

When the element is a plain rectangle, both produce identical output. The divergence starts as soon as transparency enters the picture.

When Drop Shadow Follows Shape

This is the killer feature of drop-shadow(). If your element has transparent pixels — a PNG icon with a transparent background, an SVG with open areas, a clip-path cutout, or a rotated element — drop-shadow() traces the actual visible outline.

/* box-shadow — shadows the full rectangle */
.icon {
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}

/* drop-shadow — shadows only the opaque pixels */
.icon {
  filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.3));
}

Apply both to a hamburger menu icon. box-shadow draws a rectangular shadow behind the transparent gaps between the lines. drop-shadow() casts a shadow that traces each line individually — the result looks correct.

Clip-Path Shapes

clip-path removes visual pixels but leaves the bounding box intact. box-shadow renders on the full rectangle; drop-shadow() respects the clip.

.arrow {
  clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
  filter: drop-shadow(0 6px 10px rgba(0, 0, 0, 0.3));
}

Using box-shadow here would produce a rectangular shadow behind a diamond shape — clearly wrong.

SVG and Transparent PNGs

SVGs often contain shapes with empty space between elements. A logo with cutout letterforms, an icon with a transparent center — box-shadow fills those gaps with shadow paint. drop-shadow() follows the inked pixels precisely.

Drop Shadow Syntax

filter: drop-shadow(h-offset v-offset blur color);
ValueRequiredNotes
h-offsetYesPositive shifts right, negative left
v-offsetYesPositive shifts down, negative up
blurYesMust be specified — no zero default like box-shadow
colorNo (but recommended)Browser default varies — always specify explicitly

Key differences from box-shadow syntax:

  • No spread valuedrop-shadow() cannot enlarge or shrink the shadow
  • No inset keyword — inner shadows are not supported
  • No multi-shadow — you cannot comma-separate multiple drop-shadow() values in a single filter

Stacking Multiple Drop Shadows

Chain drop-shadow() calls within a single filter property to create layered effects:

.icon {
  filter:
    drop-shadow(0 1px 2px rgba(0, 0, 0, 0.1))
    drop-shadow(0 4px 8px rgba(0, 0, 0, 0.15));
}

Each drop-shadow() renders relative to the output of the previous filter. The second shadow is cast by the element plus its first shadow — which subtly shifts the result compared to box-shadow layering where each shadow casts independently from the element bounding box.

When to Use Each

Use box-shadow When

  • The element is a rectangle with no transparency concerns — cards, modals, inputs, buttons
  • You need inset shadowsdrop-shadow() does not support inset
  • You need spread control — shrinking or growing the shadow shape
  • You need multiple shadows with independent positioning — comma syntax is cleaner
  • Performance is criticalbox-shadow composites more efficiently than filters

Use drop-shadow() When

  • The element has transparent regions — PNG/SVG icons, logos with cutouts
  • The element uses clip-path — clipped shapes need contour-following shadows
  • The element is transformed in ways that alter its rendered shape
  • You want a shadow around irregular borders — dashed or dotted borders cast uneven shadows with box-shadow

Inheritance and Composition

filter applies to the entire element and its subtree. A filter on a parent element affects all descendants as a composited group. This means:

  • drop-shadow() on a parent casts a single shadow around the combined alpha shape of the parent and all children — efficient for grouped elements
  • box-shadow on a parent only shadows the parent bounding box — children may visually extend beyond the shadow

This distinction matters for icon groups, composite components, and card layouts with overflow content.

/* Single shadow around the whole group */
.icon-group {
  filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.2));
}

/* Shadow only on the container box — children extend beyond */
.icon-group {
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}

Performance Comparison

Both properties are GPU-accelerated, but they compose differently:

Factorbox-shadowdrop-shadow()
CompositingPainted with the element layerApplied as a filter — requires an extra compositing step
Multiple shadowsSingle paint operationEach drop-shadow() is a separate filter pass
AnimationSmooth with transition or @keyframesCan trigger filter recalculation — test on low-end devices
Large blur valuesEfficient — rasterized at paint timeExpensive — blur radius multiplies compositing cost
Alpha analysisNot needed — rectangle is knownBrowser must traverse pixel alpha to compute shape

For most UI elements, the performance gap is negligible. It matters only when you animate shadows on dozens of elements simultaneously or use blur radii beyond 40px.

Common Mistakes

Using Both on the Same Element

Applying box-shadow and drop-shadow() to the same element produces a shadow of a shadow. The drop-shadow() is cast from the painted output including the box-shadow, resulting in a blurry, misaligned double shadow.

Pick one. Never combine both on the same element.

Forgetting the Blur Value

box-shadow defaults blur to 0 if omitted. drop-shadow() does not — omitting blur is a syntax error or produces unexpected results depending on the browser.

/* Valid box-shadow — blur defaults to 0 */
box-shadow: 4px 4px rgba(0, 0, 0, 0.2);

/* Invalid drop-shadow — blur is required */
filter: drop-shadow(4px 4px rgba(0, 0, 0, 0.2));

/* Correct */
filter: drop-shadow(4px 4px 0px rgba(0, 0, 0, 0.2));

Drop Shadow on Dense Layouts

Because drop-shadow() follows the alpha shape, it can produce visually noisy shadows on elements with many small transparent gaps — like text with letter-spacing or elements with detailed SVG patterns. For these cases, box-shadow on a wrapper element often produces a cleaner result.

Browser Support

FeatureChromeFirefoxSafariEdge
box-shadow10+4+5.1+12+
filter: drop-shadow()53+35+9.1+12+
backdrop-filter (glass)76+103+9+17+

drop-shadow() has slightly newer support than box-shadow, but both work in all modern browsers. No prefixes are needed.

Key Takeaways

  • box-shadow follows the bounding box; drop-shadow() follows the alpha contour — this is the deciding factor
  • drop-shadow() has no spread, no inset, and no multi-shadow comma syntax
  • Chain drop-shadow() calls in a single filter to stack alpha-aware shadows
  • Use drop-shadow() for PNG/SVG icons, clip-path shapes, and irregular forms
  • Use box-shadow for rectangular elements, inset effects, spread control, and better composition performance
  • Never combine both on the same element — pick one

Try It Yourself

Build and compare both shadow types in our CSS Box Shadow Generator. Experiment with offset, blur, and color values — then copy the generated code directly into your project.

  • CSS Box Shadow Guide — Master offset, blur, spread, inset, and multi-layer shadow patterns
  • CSS Visual Effects — Combine shadows with gradients, glow effects, and glass morphism for modern UI
  • CSS Design Tips — Practical techniques for pairing shadows with gradients and color