---
name: animated-gradient-text
description: Use when you want "Energetic, modern, expressive" - Moves gradient colors through text over time.
---

# Animated Gradient Text

> **Category:** Text  -  **Personality:** Energetic, modern, expressive
>
> **Best use:** Hero titles, AI pages
>
> **Ratings:** Professional 4/5 - Casual 4/5 - Exotic 4/5 - Visual impact 4/5 - Difficulty 2/5 - Performance cost 2/5

## What it is

Animated gradient text fills typography with a multi-colour gradient (via `background-clip: text`) and then **slides that gradient through the glyphs over time** by animating `background-position` across an over-sized fill. It is the kinetic sibling of static *Gradient Text*: same clip-to-text trick, but the colours drift continuously, which reads as energetic and "alive". Use it for hero titles, AI / product landing pages, and any single key phrase you want to draw the eye to — sparingly, on one headline rather than whole paragraphs.

## Dependencies / CDN

**None — pure CSS.** No JavaScript is required for the effect (the demo adds an optional theme switcher). The demo loads display/UI fonts, which are optional:

```html
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Schibsted+Grotesk:wght@400;500;600&family=Sora:wght@700;800&display=swap" rel="stylesheet">
```

## HTML

Wrap only the phrase you want animated — keep the rest of the heading as normal text for contrast and legibility:

```html
<h1 class="headline">
  <span class="lead">Turn one sentence into</span>
  <span class="gradient-text">software that ships itself.</span>
</h1>
```

## CSS

```css
.gradient-text{
  color:#ff7eb3;                          /* fallback if background-clip:text is unsupported */
  -webkit-box-decoration-break:clone;     /* full gradient on each line if the phrase wraps */
          box-decoration-break:clone;
}
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  .gradient-text{
    /* a colourful gradient whose FIRST and LAST stop MATCH -> the slide loops with no seam */
    background-image:linear-gradient(115deg,
      #ff4d8d 0%,#ff8a3d 16%,#ffd24d 32%,#43e6b5 50%,
      #3da8ff 66%,#9b6bff 82%,#ff4d8d 100%);
    background-size:200% auto;             /* 2x wider than the text -> room to slide */
    -webkit-background-clip:text;background-clip:text;
    color:transparent;-webkit-text-fill-color:transparent;
    animation:gt-flow 7s linear infinite;  /* drives the motion */
  }
}
@keyframes gt-flow{to{background-position:200% 50%}} /* travel one full tile -> seamless */

/* FREEZE for users who prefer reduced motion */
@media (prefers-reduced-motion:reduce){
  .gradient-text{animation:none}           /* stays a static gradient, no movement */
}
```

The demo stores the gradient in a CSS custom property on the stage (`--ngt-grad`) so a theme switcher can swap palettes live; inline a literal `linear-gradient(...)` if you don't need that.

## JavaScript

Not required for the effect. The demo's only script is an **optional** live palette switch — it just sets a `data-pal` attribute that CSS reads to change `--ngt-grad`:

```js
var stage = document.querySelector('.ngt-stage');
stage.querySelectorAll('.ngt-chip').forEach(function(chip){
  chip.addEventListener('click', function(){
    stage.querySelectorAll('.ngt-chip').forEach(function(c){
      c.classList.remove('is-on'); c.setAttribute('aria-pressed','false');
    });
    chip.classList.add('is-on'); chip.setAttribute('aria-pressed','true');
    stage.dataset.pal = chip.dataset.pal;   /* CSS: .ngt-stage[data-pal="neon"]{--ngt-grad:…} */
  });
});
```

## How it works

- **`background-clip: text` + `color: transparent`** paints the element's background *only inside the glyph shapes*, so the gradient becomes the letters' fill.
- **`background-size: 200% auto`** makes the gradient image twice the text's width, leaving off-screen colour to scroll into view.
- **`@keyframes` animating `background-position` to `200%`** slides the over-sized fill by exactly one full tile per cycle. Because the gradient's first and last colour stops are identical and the background tiles (`background-repeat` defaults to `repeat`), the loop point is visually identical to the start — **no seam, no jump**.
- The animation only touches `background-position`, never the text or layout, so glyphs stay perfectly crisp while the colour moves.

## Customization

- **Speed:** the `animation` duration — `4s` feels lively, `10s`+ is a slow ambient drift.
- **Direction:** animate to `-200%` (or flip the gradient `deg`) to reverse the flow.
- **Palette / personality:** swap the gradient stops. The demo ships three (Aurora / Sunset / Neon); keep first stop == last stop to preserve the seamless loop.
- **Intensity of travel:** larger `background-size` (e.g. `300%`) packs more colour into one pass; match the keyframe end value to the size (`300%`).
- **Scope:** apply to one hero word, a small mono label, or a bar fill (the demo reuses `--ngt-grad` on its progress bar) — but avoid running it on long body copy.

## Accessibility & performance

- **Reduced motion:** gated behind `@media (prefers-reduced-motion: reduce)`, which sets `animation: none` so the gradient **freezes** on a static frame (still attractive, just not moving).
- **Always provide a solid `color` fallback** before the `@supports` block; browsers without `background-clip: text` (and Windows high-contrast / `forced-colors` mode, which can drop the gradient) then show legible solid text instead of invisible glyphs.
- **Contrast:** pick gradient stops that all clear contrast against the background — the lightest *and* darkest stop both become text, so don't let either fall below your contrast floor.
- **Cost:** `background-position` animates on the main thread (it's a paint, not a GPU-composited transform), so it is cheap on a headline-sized region but should not be applied to large or numerous elements.

## Gotchas

- **`-webkit-background-clip: text` is mandatory** for Safari/iOS and Chromium; omit it and the gradient paints a rectangle instead of the letters.
- **`-webkit-text-fill-color: transparent`** is the reliable way to hide the glyph fill in WebKit — `color: transparent` alone is ignored by `text-fill-color` when set.
- **Seamless loop = matching end stops + travelling a whole tile.** Mismatched first/last colours, or animating to `100%` instead of `200%` with a `200%` size, produces a visible snap each cycle.
- **Wrapping text** needs `box-decoration-break: clone`, or a multi-line phrase shares one gradient box and the lower lines look washed out.
- Don't animate `background-size` or the gradient's colour stops (those trigger expensive re-rasterisation) — only animate `background-position`.
