Browse by section

Web Design 日本語

CSS Shadows: box-shadow vs text-shadow vs drop-shadow

There are three ways to add a shadow in CSS: box-shadow, text-shadow and filter: drop-shadow().

The short answer: use box-shadow to cast a shadow from an element’s rectangular box, text-shadow for text, and drop-shadow() when the shadow must follow the shape of a cut-out image or icon.

All three are one-liners, and they differ in the order of their values and in what shape the shadow takes. Get that wrong and a shadow you meant to trace a transparent PNG comes out as a rectangle.

Sponsored

How does box-shadow work?

The short answer: the shadow takes the shape of the element’s box. If the element has rounded corners, so does the shadow.

box-shadow: [inset] offset-x offset-y [blur] [spread] [color];
Value Optional? Meaning
inset Yes Casts the shadow inside the element. Goes first if used
offset-x No Distance to the right. Negative moves left
offset-y No Distance down. Negative moves up
blur Yes Larger is softer. 0 gives a hard edge
spread Yes Grows or shrinks the shadow itself. Negative shrinks it
color Yes Falls back to the color property if omitted

Only the two offsets are required. Give just those two and you get a hard-edged shadow with no blur.

.shadow-box {
  box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.3);
}

A hard shadow on an image

See the Pen
box-shadow
by りん@エンジニア (@rinblog0408)
on CodePen.

For a crisp shadow behind an image or a block, set the blur to 0 and give it a colour.

.shadow {
  box-shadow: 10px 10px 0 #c3a400;
}

How does text-shadow work?

The short answer: it shadows the glyphs themselves, and unlike box-shadow it supports neither inset nor spread.

text-shadow: offset-x offset-y [blur] [color];
.shadow-text {
  text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.3);
}

Offset text shadows for headings

See the Pen
shadow-text
by りん@エンジニア (@rinblog0408)
on CodePen.

The offset shadow you often see on headings is also one line. Set the blur to 0 and pick a definite colour.

.shadow {
  text-shadow: 4px 4px 0 #c3a400;
}

Sponsored

Stacking several shadows with commas

The short answer: you can layer as many shadows as you like, separated by commas. The first one listed is painted on top.

.shadow-box {
  box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.3), -5px -5px 5px rgba(0, 0, 0, 0.3);
}

text-shadow works the same way. Splitting a light shadow to the top left and a dark one to the bottom right, to fake depth, is an application of this.

What is the difference between blur and spread?

The short answer: blur softens the shadow’s edge, spread changes the size of the shadow itself. They sit next to each other as the third and fourth values and do completely different things.

/* base: blur only */
.shadow-box {
  box-shadow: 0 5px 5px rgba(0, 0, 0, 0.3);
}

/* more blur: the edge softens and spreads out */
.shadow-box.blur {
  box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
}

/* add spread: the shadow itself gets bigger */
.shadow-box.spread {
  box-shadow: 0 5px 5px 8px rgba(0, 0, 0, 0.3);
}

/* negative spread: the shadow contracts */
.shadow-box.shrink {
  box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.3);
}

Negative spread is the one that earns its keep in real work. Push the blur up and pull the spread negative and the shadow gathers under the element, which reads as the element floating.

Sponsored

Using drop-shadow to follow a shape

See the Pen
filter:drop-shadow
by りん@エンジニア (@rinblog0408)
on CodePen.

The short answer: for a transparent PNG icon or an element cut out with clip-path, use filter: drop-shadow().

Where box-shadow casts from the element’s rectangular box, drop-shadow() follows the opaque parts of the image, meaning its alpha channel.

.shadow {
  filter: drop-shadow(10px 10px 0 #c3a400);
}

Apply box-shadow to a transparent PNG and you get a shadow of the rectangle, not of the artwork. That is the cause of most “why does my shadow look wrong” problems.

Two things to watch with drop-shadow

The short answer: drop-shadow() has no inset and no spread. You get two offsets, a blur radius and a colour.

The second difference is that the blur radius is interpreted differently. The third value of drop-shadow() is treated as the standard deviation of a Gaussian blur, so the same number looks noticeably softer than it does in box-shadow. Copying values across changes the look, so adjust by eye.

You can also apply several, by writing drop-shadow(...) drop-shadow(...) separated by spaces. Note that this is spaces, not commas as with box-shadow.

Which of the three should you use?

The short answer: ask whether the thing you are shadowing is a box, some text, or a cut-out shape.

Item box-shadow text-shadow drop-shadow()
Shadow shape The element’s box The glyphs The opaque pixels
Blur Yes Yes Yes, softer for the same value
Spread Yes No No
inset Yes No No
Multiple shadows Comma separated Comma separated Space separated
Typical use Cards, buttons, inputs Headings, logo text Transparent PNGs, icons, cut-outs

In practice, cards and buttons take box-shadow, headline copy takes text-shadow, and logos or illustrations take drop-shadow(). That split covers nearly everything.

When you are shadowing images inside a card grid, using object-fit to fill the width and crop without distortion handles the image sizing side, and the 2024 CSS Grid updates cover the layout around them.