CSS Gradient Text

Text filled with a gradient using background-clip:text.

Published May 19, 2026 Beginner 7 min read

CSS gradient text is a background painted behind an element and then clipped to the shape of its letters. background-clip: text does the clipping and color: transparent gets the normal text color out of the way so the clipped background shows through. Miss the second declaration and nothing appears to happen at all, because the solid text color is painted directly on top of the gradient.

The same two lines work with any background: a linear gradient, a conic one, a repeating stripe pattern, or a photograph. Animating background-position behind the clip makes the colors flow through the letters without the text itself ever moving. The variants below cover a conic fill, a striped fill, and a split color headline with a hard stop instead of a blend.

Gradient filled type

Gradient Text Multi Color Animated Flow

HTML

<span class="grad">Gradient Text</span>
<span class="grad-2">Multi Color</span>
<span class="grad-animated">Animated Flow</span>

CSS

/* Two-color fill */
.grad {
  display: inline-block;
  font-size: 2.5rem;
  font-weight: 800;
  background: linear-gradient(90deg, #b8ff57, #38bdf8);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

/* Same trick, more color stops */
.grad-2 {
  display: inline-block;
  font-size: 2.5rem;
  font-weight: 800;
  background: linear-gradient(90deg, #b8ff57, #57d9a3, #38bdf8, #c084fc, #f472b6);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

/* An oversized background can slide behind the letters */
.grad-animated {
  display: inline-block;
  font-size: 2.5rem;
  font-weight: 800;
  background: linear-gradient(90deg,
    #b8ff57, #57d9a3, #38bdf8, #c084fc, #f472b6
  );
  background-size: 400% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  animation: gradient-shift 3s ease-in-out infinite alternate;
}

@keyframes gradient-shift {
  from { background-position: 0% 50%; }
  to   { background-position: 100% 50%; }
}

Other ways to build it

Any background, not only a linear gradient

The clip does not care what kind of background it is clipping. A conic-gradient sweeps color around a center point, so the letters sample a rotation rather than a straight run. A repeating-linear-gradient with hard stops produces stripes, and the angle decides whether they read as diagonal hatching or as horizontal banding. Everything else in the rule stays identical.

Conic Fill Striped Fill

HTML

<div class="grad-variants">
  <span class="grad-conic">Conic Fill</span>
  <span class="grad-stripes">Striped Fill</span>
</div>

CSS

.grad-conic {
  display: inline-block;
  font-size: 2.5rem;
  font-weight: 800;
  background: conic-gradient(from 180deg at 50% 50%,
    #38bdf8, #c084fc, #f472b6, #ffd444, #b8ff57, #38bdf8
  );
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

/* hard stops, so the colors band instead of blending */
.grad-stripes {
  display: inline-block;
  font-size: 2.5rem;
  font-weight: 800;
  background: repeating-linear-gradient(45deg,
    #b8ff57 0 8px,
    #57d9a3 8px 16px
  );
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

Split fill, with a fallback that cannot go blank

Two stops at the same position give a hard edge instead of a blend, so the top half of every letter is one color and the bottom half another. The rule is also written the safe way round: a solid color is set first, and only the transparent fill and the clip live inside @supports. A browser that cannot clip a background to text never sees the transparent declaration, so it renders a solid heading rather than an empty gap.

Split Fill

HTML

<div class="grad-variants">
  <span class="grad-split">Split Fill</span>
</div>

CSS

/* the fallback everyone gets */
.grad-split {
  display: inline-block;
  font-size: 2.5rem;
  font-weight: 800;
  /* tight leading, so the stop lands across the middle of the glyphs */
  line-height: 1;
  color: #b8ff57;
}

/* the transparent fill only applies where the clip actually works */
@supports (background-clip: text) or (-webkit-background-clip: text) {
  .grad-split {
    /* both stops at 50%, so the color changes with no blend between */
    background: linear-gradient(#38bdf8 0 50%, #b8ff57 50% 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }
}

/* forced colors replace the background but can keep the transparent
   fill, which would leave nothing on screen */
@media (forced-colors: active) {
  .grad-split {
    -webkit-text-fill-color: currentColor;
    color: CanvasText;
  }
}

How it works

The gradient is applied to the background property, then background-clip:text clips it to the shape of the text. Setting color:transparent (or -webkit-text-fill-color:transparent) makes the text itself invisible, revealing the gradient behind it. Animating background-position creates the flowing color effect.

Four declarations make up the whole technique. background paints the gradient across the element's box. -webkit-background-clip: text and background-clip: text limit where that background is drawn to the glyph shapes. -webkit-text-fill-color: transparent and color: transparent remove the paint that would otherwise cover it. Both pairs are written because the prefixed forms are what older Safari and Chrome understood, and the unprefixed ones are the standard.

display: inline-block is on every rule here for a reason. An inline element that wraps across two lines gets a fragmented background box, and the gradient restarts on each fragment, so a two line headline shows the full color sweep twice. Making the element a block or an inline-block gives it one continuous box and one continuous gradient.

The gradient covers the element's padding box, not the letters. That has a visible consequence: a short word inside a wide container only sees the slice of the gradient that happens to fall under it. If a heading looks washed out compared to the design, the container is usually wider than the text, and the fix is to shrink the box with inline-block or width: fit-content rather than to change the color stops.

Animation works by giving the background more room than the box and then sliding it. background-size: 400% 100% makes the gradient four times the element's width, and @keyframes moves background-position from 0% to 100%. The letters never move. Only the paint behind them does, which is why the effect stays cheap even at a large font size.

The clip is not limited to gradients. background-image: url(photo.jpg) with the same two clip declarations fills the type with a photograph, and background-size: cover scales it. The one thing to watch is contrast, since a busy image behind thin letterforms leaves nothing readable.

CSS properties used

background-clip
text restricts the background to the shape of the glyphs. The -webkit- prefixed form is still worth writing alongside it.
color
transparent removes the text's own paint so the clipped background is visible. Without it the gradient is completely hidden.
-webkit-text-fill-color
A prefixed property that overrides color for the glyph fill. Setting it to transparent covers browsers that honour it in preference to color.
background-size
Sizing the gradient larger than the element, typically 400% 100%, is what leaves room for the animation to slide it.
background-position
The property the keyframes animate. Moving it shifts which part of the oversized gradient sits behind the letters.
display
inline-block gives the element a single unbroken background box, so the gradient does not restart on a second line.

Browser support

FeatureChromeFirefoxSafariEdge
background-clip: text44915.512
-webkit-text-fill-color4493.115
conic-gradient698312.179
animation455.112
@supports2822912

Can I Use records full unprefixed background-clip: text in Chrome from 4, Firefox from 49, Edge from 12 and Safari only from 15.5. Every Chrome and Edge version still carries a note that the prefixed -webkit-background-clip is what is actually implemented, and Safari before 15.5 supported it only in the prefixed form. Writing both is therefore not legacy noise, it is what makes the effect work in shipping browsers today. The -webkit-text-fill-color row is tracked on Can I Use under CSS text-stroke and text-fill, which is why its Safari number is so much older.

Accessibility notes

Text filled with a gradient has no single foreground color, so a contrast ratio cannot be calculated for it in the usual way. The honest approach is to check the lightest stop in the gradient against the background and treat that as the ratio, because the lightest part is where the text is hardest to read. On a dark page that means watching the darkest stop instead.

Windows High Contrast Mode and the forced colors setting replace author colors with a system pair. color: transparent survives that replacement in some implementations and the background does not, which leaves an invisible heading. Guarding the transparent fill inside a @media (forced-colors: active) block that restores a solid color costs three lines and removes the failure mode.

The text itself is untouched by all of this. It is selectable, searchable, translatable, and read out normally by a screen reader, which is the main reason to prefer this over setting a heading as an image. Anyone who turns off CSS or loads the page through a reader mode gets plain readable type.

What you can build with it

  • Hero headlines. One large phrase carrying the brand gradient, with the rest of the page in a solid color so the effect stays rare enough to read as deliberate.
  • Statistics and counters. A large figure filled with a gradient reads as a highlight without needing a colored card behind it.
  • Logotype in text. A wordmark that stays real text, so it is selectable and indexable, unlike the same wordmark exported as an SVG or a PNG.
  • Section labels. Small uppercase labels with a two stop fill, where the gradient runs across a short word and reads almost as a single blended color.
  • Animated calls to action. A slowly shifting fill draws the eye to one button label. Paired with the neon text effect it becomes a full display treatment.

Mistakes worth avoiding

  • Leaving out color: transparent. The solid text color paints on top of the clipped background, so the gradient is there and completely invisible.
  • Skipping the -webkit- prefixed declarations. In browsers that only implement the prefixed form you get transparent text on no background, which is a blank space where the heading should be.
  • Applying the effect to an inline element that wraps. Each line fragment gets its own background box, so the gradient restarts halfway through the headline.
  • Using a container much wider than the text. The letters only sample the slice of the gradient that falls behind them, so a five color gradient can come out looking like one flat color.
  • Animating background-size instead of background-position. Resizing the background re-rasterises it every frame, which is visibly slower than sliding one that is already the right size.

Frequently asked questions

How do you make gradient text in CSS?
Give the element a background that is a gradient, add -webkit-background-clip: text and background-clip: text, then set -webkit-text-fill-color: transparent and color: transparent. The background is clipped to the glyph shapes and the transparent fill lets it show through.
Why is my gradient text invisible?
Two causes account for nearly all of it. Either the browser does not support background-clip: text in the form you wrote, so it clips nothing while the transparent fill still applies, or a later rule is setting color back to a solid value. Guard the transparent declarations inside @supports and the first case degrades to plain readable text.
Does background-clip: text still need the webkit prefix?
Yes, in practice. Can I Use lists Chrome and Edge as supporting the property while noting that the prefixed -webkit-background-clip is the implemented form, and Safari only reached unprefixed support at 15.5. Writing both declarations together is one extra line and covers every shipping browser.
Can you put an image inside text with CSS?
Yes. Swap the gradient for background-image: url(photo.jpg) and keep the same clip and transparent fill declarations. Add background-size: cover so the picture scales to the text box. Contrast is the limiting factor, since a detailed photograph behind thin letters is hard to read.
Is gradient text bad for accessibility or SEO?
For SEO it is fine, since the text is ordinary markup that crawlers read normally. For accessibility the two things to handle are contrast, measured against the least readable stop in the gradient, and forced colors mode, where a transparent fill with no background can leave the heading invisible.