# CSS text shadow: syntax, examples and better options

[Canonical HTML page](https://gradiently.design/guide/css-text-shadow)

text-shadow is a small property with a big reputation for rescuing unreadable headlines. It is better at decoration than rescue. Here is the syntax, a handful of styles worth copying, and what to use when legibility is the real problem.

## The short version

- The CSS text shadow property takes a horizontal offset, a vertical offset, an optional blur radius and a colour.
- Several shadows can be stacked on one piece of text by separating them with commas, and the first one listed is drawn on top.
- Unlike box-shadow, text-shadow has no spread value and no inset keyword.
- Hard offset shadows with no blur are the most useful decorative style, from retro headlines to long shadows.
- A soft dark shadow is a weak fix for text over a busy image; a scrim, a darker image or a calmer background does the job properly.

A **CSS text shadow** is written `text-shadow: 2px 2px 4px rgb(0 0 0 / 0.4)`: a horizontal offset, a vertical offset, an optional blur radius and a colour. Separate several shadows with commas to stack them. It is excellent for decorative effects such as crisp offset headlines, long shadows and faux outlines. It is a poor tool for making text readable over a busy photo, and the better options for that are further down.

## text-shadow syntax

```css
/* offset-x | offset-y | blur-radius | color */
h1 { text-shadow: 2px 3px 6px rgb(0 0 0 / 0.35); }

/* No blur: a hard copy of the letters */
h1 { text-shadow: 3px 3px 0 #f97316; }

/* Colour first is also valid */
h1 { text-shadow: #f97316 3px 3px; }

/* Several shadows: the first is drawn on top */
h1 { text-shadow: 2px 2px 0 #fde68a, 4px 4px 0 #f97316; }

/* Remove an inherited shadow */
h1 { text-shadow: none; }
```

The full grammar in five lines. Lengths can be negative to throw the shadow up or to the left.

| Part | Required | What it does |
| --- | --- | --- |
| Horizontal offset | Yes | Positive moves the shadow right, negative moves it left |
| Vertical offset | Yes | Positive moves it down, negative moves it up |
| Blur radius | No | Defaults to 0, a hard edge. Cannot be negative |
| Colour | No | Defaults to the text colour, `currentcolor` |

There is no spread and no `inset` here. Those belong to [box-shadow](https://gradiently.design/guide/css-box-shadow), which shadows the element's box rather than its letters.

The shadow is painted behind the text and takes the shape of every glyph, including underlines and decorations. It does not change layout: a large offset can spill outside the element and overlap neighbours without pushing them away, so leave room with padding if the shadow is big.

## Text shadow examples worth copying

The styles that hold up are the hard edged ones. A shadow with no blur reads as a deliberate graphic choice; a soft grey blur under body text tends to read as a mistake.

```css
/* 1. Subtle lift for large display type on a light page */
.lift { text-shadow: 0 1px 0 rgb(255 255 255 / 0.6), 0 2px 3px rgb(15 23 42 / 0.18); }

/* 2. Retro offset in a second colour */
.retro { color: #1e1b4b; text-shadow: 4px 4px 0 #f472b6; }

/* 3. Double offset, poster style */
.double { color: #fff7ed; text-shadow: 3px 3px 0 #f97316, 6px 6px 0 #7c2d12; }

/* 4. Long shadow: many 1px steps */
.long {
  color: #fef3c7;
  text-shadow: 1px 1px 0 #b45309, 2px 2px 0 #b45309, 3px 3px 0 #b45309,
    4px 4px 0 #b45309, 5px 5px 0 #b45309, 6px 6px 0 #b45309,
    7px 7px 0 #b45309, 8px 8px 0 #b45309;
}

/* 5. Pressed in: a light edge below dark text on a mid tone */
.pressed { color: #334155; text-shadow: 0 1px 0 rgb(255 255 255 / 0.45); }
```

Five styles that work. The long shadow is just the same hard shadow repeated one pixel further each time.

Retro offsets and long shadows are covered visually in [retro text effects](https://gradiently.design/guide/retro-text-effect) and [3D text effects](https://gradiently.design/guide/3d-text-effect). For a clean outline, prefer `-webkit-text-stroke` with `paint-order: stroke fill` over the old trick of four shadows at each corner, which leaves gaps on curves; [outline text](https://gradiently.design/guide/outline-text) shows both.

- Indigo letters: #1e1b4b
- Pink offset: #f472b6
- Cream letters: #fff7ed
- Orange first step: #f97316
- Rust second step: #7c2d12

The colours behind the retro and double offset examples. Offset shadows work best when the shadow colour is clearly different from the letters, not a darker copy of them.

## Why a soft shadow is a weak legibility fix

The common use of `text-shadow` is a dark blur behind white text over a photo, hoping to separate the two. It helps a little at the edges of each letter and does nothing for the space inside them, where the photo still shows through at full strength. Push the blur and opacity up until it works and you get a smudge around every word. Glows around text, light or dark, look dated and still fail on the brightest parts of the image.

Contrast checkers also ignore shadows. They measure the text colour against the background colour, so a headline that only passes thanks to its shadow will be flagged in an audit, and with good reason. The thresholds are in [colour contrast and accessibility](https://gradiently.design/guide/color-contrast-accessibility).

### Shadow as a crutch

- Blurred black halo behind white text
- Fails wherever the image is brightest
- Contrast tools still report a failure
- Muddy edges on small text

### Fix the background

- A gradient scrim under the words
- Darken or desaturate the image
- Move text to the calmest area
- Choose a background designed to carry words

## Better options for text on images and gradients

A scrim is a gradient that darkens only the part of the image behind the text, fading to nothing elsewhere. It keeps the photo bright where it matters and gives every letter the same calm ground. [Gradient overlays in CSS](https://gradiently.design/guide/css-gradient-overlay) covers the layering in full.

Bottom scrim for captions: `linear-gradient(to top, rgb(2 6 23 / 0.78) 0%, rgb(2 6 23 / 0.45) 35%, rgb(2 6 23 / 0) 70%)`

Dark at the foot, clear by two thirds of the way up. Layer it over a photo and set caption text in the bottom third.

```css
.card {
  background-image:
    linear-gradient(to top, rgb(2 6 23 / 0.78), rgb(2 6 23 / 0) 70%),
    url("/images/harbour.jpg");
  background-size: cover;
  background-position: center;
  color: #f8fafc;
}
```

The scrim as the top background layer, the photo beneath. No shadow needed on the text.

Other reliable options: run the image through `filter: brightness(0.75)` on its own layer, crop so the words land on sky or wall rather than detail, or set the text on a solid band. [Text over images](https://gradiently.design/guide/text-over-image) walks through each with examples.

A portrait post with a cream headline crossing a bright patch of gradient and losing contrast

Light words over the brightest part of the background. A shadow would only blur the problem.

The same portrait post with the gradient deepening behind the headline so it reads clearly

The background deepens behind the line instead, so the words read without any effect on them.

This is exactly the job Gradiently's Marks do by themselves: the calmest region moves behind your words and Auto ink picks light or dark type line by line, with no shadow, box or blur. When you want shadow as decoration rather than repair, its lettering treatments such as Extrude, Double and Trail give you offset styles without writing a single shadow.

## Text shadow on gradient text

Gradient text is made with `background-clip: text` and a transparent text colour. Add a `text-shadow` to it and the shadow shows straight through the transparent letters, muddying the gradient from inside. The fix is to shadow the element instead: `filter: drop-shadow(3px 3px 0 #1e1b4b)` follows the painted shape of the letters and sits behind them. The technique itself is covered in [gradient text in CSS](https://gradiently.design/guide/css-gradient-text).

> **One shadow per drop-shadow()** `drop-shadow()` takes one shadow per function, but you can chain several: `filter: drop-shadow(2px 2px 0 #f97316) drop-shadow(2px 2px 0 #7c2d12)`. Each one shadows the result of the last.

## Performance and animation

Hard shadows are cheap. Large blur radii on long passages of text cost more to paint, and animating `text-shadow` repaints the text on every frame. If you want a headline to animate, move it with `transform` and keep the shadow fixed.

## FAQ

### What is the syntax for text-shadow in CSS?

`text-shadow: offset-x offset-y blur-radius color`, for example `2px 2px 4px #000`. Only the two offsets are required.

### Can I add more than one text shadow?

Yes. Separate shadows with commas. The first one in the list is painted on top of the others.

### Does text-shadow have a spread value?

No. Spread and `inset` exist only on `box-shadow`. To thicken a text shadow, stack several shadows with small offsets.

### Does text-shadow improve accessibility?

Not reliably. Contrast checks ignore shadows, so text must reach the required contrast against its background without one.

### How do I make white text readable on a photo without text-shadow?

Layer a dark gradient scrim behind the text area, darken the image, or place the words over a calm part of the photo.
