20 CSS Text Gradient Effects 08 / 20

Animated Moving Text Gradient Background CSS

A hero section where the gradient background-position animates continuously across a 300%-wide gradient, creating a shifting colour sweep through the text.

Pure CSS MIT licensed
Live Demo Open in tab
Open in playground

The code

<div class="tg-08">
  <div class="tg-08__hero">
    <div class="tg-08__tag">✦ New — Season 3</div>
    <h1 class="tg-08__title">The Future<br>of <span class="tg-08__anim-grad">Interface</span><br>Design</h1>
    <p class="tg-08__sub">Shifting gradients create motion and energy without a single line of JavaScript.</p>
  </div>
</div>
.tg-08, .tg-08 *, .tg-08 *::before, .tg-08 *::after { margin:0; padding:0; box-sizing:border-box; }
.tg-08 ::selection { background:#7c3aed55; color:#fff; }

.tg-08 {
  --c1: #f0abfc;
  --c2: #818cf8;
  --c3: #38bdf8;
  --c4: #34d399;
  --bg: #0a0a12;
  --text: #f8fafc;
  --muted: #94a3b8;
  font-family: system-ui, -apple-system, sans-serif;
  background: var(--bg);
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 48px 24px;
}

.tg-08__hero { text-align: center; max-width: 600px; }

.tg-08__tag {
  display: inline-block;
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .1em;
  color: var(--muted);
  margin-bottom: 24px;
}

.tg-08__title {
  font-size: clamp(2.5rem, 8vw, 4.5rem);
  font-weight: 900;
  line-height: 1.08;
  letter-spacing: -.04em;
  color: var(--text);
  margin-bottom: 20px;
}

/*
  Moving gradient: background-size is 300% wide so the 
  gradient has room to travel. background-position animates
  from 0% to 100%, which pans across the extended gradient.
  background-clip:text exposes it through the letterforms.
*/
.tg-08__anim-grad {
  background: linear-gradient(
    90deg,
    var(--c1) 0%,
    var(--c2) 25%,
    var(--c3) 50%,
    var(--c4) 75%,
    var(--c1) 100%
  );
  background-size: 300% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  animation: tg-08-shift 4s linear infinite;
}

@keyframes tg-08-shift {
  0%   { background-position: 0% 50%; }
  100% { background-position: 100% 50%; }
}

.tg-08__sub {
  font-size: 1rem;
  color: var(--muted);
  line-height: 1.7;
  max-width: 480px;
  margin: 0 auto;
}

@media (prefers-reduced-motion: reduce) {
  .tg-08__anim-grad {
    animation: none;
    background-position: 0% 50%;
  }
}

How this works

The moving gradient uses an extended background-size: 300% 100% which makes the gradient three times wider than the element. The @keyframes tg-08-shift animation moves background-position from 0% 50% to 100% 50% linearly and infinitely. Because the gradient is cyclic (it repeats the first colour at 100%), the transition is seamless with no visible seam.

Only the background-position property is animated. This is a compositor-friendly operation — the browser can perform it without triggering layout or paint phases. Combined with -webkit-background-clip: text, the shifting position is visible only through the letterforms, creating the illusion of light sweeping through the text.

Customize

  • Control animation speed by editing 4s in animation: tg-08-shift 4s linear infinite — slower values (8s) feel meditative, faster (1.5s) feel energetic.
  • Add more colour stops to the gradient — insert hues between existing stops and expand background-size to 400% to keep the sweep speed consistent with more colours.
  • Change linear timing to ease-in-out for a breathing quality — the sweep accelerates into and out of the highlight band instead of moving at constant speed.
  • Apply the same animated gradient to a subtitle or tag by adding the tg-08__anim-grad class, adjusting the gradient stops to complementary colours for a multi-element sequence.
  • Pause the animation on hover by adding .tg-08__anim-grad:hover { animation-play-state: paused; } so users can 'freeze' the gradient at their preferred colour point.

Watch out for

  • The background-position animation approach requires background-size: 300% 100% — if you forget to set this, the gradient won't appear to move because the default 100% size leaves no room for the position to scroll.
  • Using linear timing on the position animation creates a seamless loop only when the gradient's first and last colour stops match. If they differ, the jump at the loop boundary will be visible — always make the final stop equal the initial stop.
  • On Safari, very long text strings with animated background-position and background-clip: text can cause a brief repaint flash on loop iteration. Limit the animation to short display words (<10 characters) for the smoothest result.

Browser support

ChromeSafariFirefoxEdge
69+ 12.1+ 83+ 69+

background-position animation on background-clip:text elements is reliable in modern browsers; avoid pairing with simultaneous transforms on the same element in Safari.

Search CodeFronts

Loading…