Colour · gradient recipeCSS gradient text — how to make it
The gradient is set as a background and clipped to the shape of the letters. Below are a live example, code with a fallback for older browsers and why the text sometimes disappears.
Set the gradient as the element’s background, as for any block.
02
background-clip: text
Clip the background to the outline of the letters. Safari needs the -webkit- prefix.
03
-webkit-text-fill-color: transparent
Make the letter fill transparent so the background shows through.
04
@supports (…)
Wrap the rule in a support check so older browsers keep a plain colour.
04
Common mistakes
The text vanished
The transparent fill is set but background-clip did not apply. Without @supports the text becomes invisible — always keep a fallback color.
Gradient spans the whole line
A block element’s background stretches across the full width, and the letters only get a slice of the transition. Use display: inline-block.
Selection is invisible
With a transparent fill the selection highlight can disappear. Set ::selection with an opaque colour.
05
Frequently asked
Safari long understood only the prefixed property, so the rule needs both lines: -webkit-background-clip: text and background-clip: text. The transparent letter fill also comes from the prefixed -webkit-text-fill-color: transparent, which every modern browser supports. Forget the prefix and Safari shows a gradient rectangle instead of letters, or transparent text with no background. The recipe code already has both forms, and the @supports check covers either.
An inline element paints its background per line, and by default the gradient stretches over the whole phrase and is then cut into pieces. To give every line the full transition, add box-decoration-break: clone with the -webkit- prefix. For a heading over several lines it is simpler to keep display: inline-block: the gradient then covers the whole block at once and runs across the width of the longest line.
A plain text-shadow does not work here: the letter fill is transparent, so the shadow shows through it and repaints the gradient. Use filter: drop-shadow(0 2px 4px rgba(0, 0, 0, .25)) on the element itself — the filter builds the shadow from the letters already painted and stays outside them. Another option is duplicating the text in a pseudo-element with a shadow underneath, but that is extra markup for the same result.
Yes: it is ordinary text rather than an image, so it can be selected, copied, found with page search and read by screen readers. The one issue is that with a transparent fill the selection can be nearly invisible, because the highlight lies under transparent letters. Set ::selection with an opaque text and background colour and the selected part becomes readable. Search engine indexing does not suffer from the trick either.
Make the background wider than the text with background-size: 200% 100% and move background-position in @keyframes — the letters stay put while the colours travel inside them. Browsers do not animate a gradient between values, but they do animate the background position. Remember the @media (prefers-reduced-motion: reduce) block with animation: none. A ready animation skeleton is on the “Animated gradient” recipe page and combines with this one.
Screen readers read it as normal text, but eyes may get different contrast in different letters. Check the whole transition against the page background, not one colour: the light end of a gradient on white easily drops below 4.5:1. Headings larger than 24 pixels need only 3:1. A good rule is that both ends of the gradient must pass the threshold on their own, and then the middle will pass too.