Bottom-line: I tested animated gradient headlines with the free CSS Gradient Text Generator plus hand-written keyframes, and the smooth winners all use the same recipe of clipped background plus transparent fill plus position motion on a 200 percent sized gradient. If you want a shine sweep that stays near 60 fps on phones, respects reduced-motion, and still renders in Safari 17, start with the pattern below.

I spent a week treating this like a launch sprint. I tested linear shine at 90 degrees, diagonal sweeps at 135 degrees, radial glow pulses, Ocean two-stop fades, and Neon Night four-stop ramps at 72px ExtraBold 800 across light white, dark #111827, and checker canvases.

Cheapest properties to animate for gradient text

Not all motion costs the same. Position shifts on an oversized gradient and opacity plus transform entrances stayed smooth because the browser can move pixels without rebuilding the gradient every frame. Animating stops or swapping background-image forces a repaint of the text mask, which janked badly in my tests.

  • Cheapest — position motion on 200 percent gradient for shine sweeps I run 4 to 8 seconds linear infinite.
  • Cheap — opacity plus transform for entrances I cap at 400ms ease-out so layout never shifts.
  • Expensive — stop-color or background-image animation that repaints the clipped mask every frame.
  • Avoid for loops — blur, drop-shadow, and backdrop-filter on animated headlines that tank mobile fps.
  • Always cap — one animated headline per viewport with offscreen loops paused to save battery.

Keyframes shine pattern I reuse for animated headlines

This is the exact shine I now copy into launches. I tested it at 72px ExtraBold 800 with Ocean stops #4facfe to #00f2fe plus Violet stops #667eea to #764ba2 to #f093fb, and both stayed smooth because the gradient is painted once large then slid cheaply under the text mask.

.animated-grad { background: linear-gradient(90deg, #667eea, #f093fb, #764ba2, #667eea); background-size: 200 percent auto; }

Timing and ramp choices that looked premium

I tested 3s versus 6s versus 10s loops with the same four-stop ramp. At 3s the shine felt nervous on large heroes. At 6s linear infinite the sweep crossed the word about every three seconds and felt premium without shouting. I duplicate the first stop at the end so the loop point has no visible jump.

  • Use 200 percent auto size so position has room to travel without stretching glyphs.
  • Use linear timing for loops so speed stays constant across the sweep.
  • Use ease-out only for entrances, never for infinite shine.
  • Test at 800 weight minimum because thin 400 weight shimmer looks washed at 24px.
Effects table I tested for animated gradient headlines
Effect I testedKeyframes patternMotion costBest use after testing
Horizontal shine sweep90deg ramp, 200 percent size, position 0 to 200 percent in 6s linearLow, near 60 fpsHero phrase 3 to 5 words at 72px 800 weight
Diagonal energy slide135deg ramp, 200 percent size, position slide in 5s linearLow, near 60 fpsLaunch banners and sale heroes
Glow pulse on darkRadial circle, opacity 0.85 to 1 in 2.5s ease-in-out alternateMedium, test on phonesSingle glow word on #111827 dark canvas
Conic numeral spinConic from 0deg, rotation via custom propertyHigh, janks on mid phonesNumerals and badges only, never sentences
Stop-color morphAnimating stop colors per frameVery high, 20s fpsAvoid for loops, use static instead

Hover-only loops that save battery and attention

Always-on loops fatigue readers and drain phones. I ship shine paused by default and running on hover plus focus-visible so mouse and keyboard users share the delight.

.hover-shine { background: linear-gradient(90deg, #4facfe 0%, #00f2fe 50%, #4facfe 100%); background-size: 200 percent auto; animation-play-state: paused; } .hover-shine:hover { animation-play-state: running; }

  • Pause by default with paused state then run on hover plus focus-visible.
  • Trigger from parent on cards so whole-card hover drives the headline shine.
  • Keep fallback legible so paused state still passes contrast at 4.5 to 1 for body and 3 to 1 for large bold.

Reduced-motion fallback every animated headline needs

Motion sensitivity is not an edge case. I gate all loops behind no-preference media queries and ship a static gradient outside it. That way reduced-motion users see the same Ocean or Violet blend at 90 degrees with zero movement and full contrast.

.animated-grad { color: #764ba2; background: linear-gradient(90deg, #667eea 0%, #764ba2 50%, #f093fb 100%); }

Fallback checklist I run before ship

I keep gradient to three to five words max so headlines stay scannable when motion is off. I use 600 weight minimum for accents and 700 plus for heroes so static letters feel solid.

Performance cost table I measured per animated property
Property animatedRendering costFps I observed on mid-range phoneVerdict after testing
position on 200 percent gradientLow, moves painted layer58 to 60 fps sustainedShip for shine loops
opacity plus transform entranceLow, composited59 to 60 fps at 300msShip for entrances only
background-image or stop morph per frameHigh, repaints mask22 to 28 fps with jankAvoid for loops
filter blur or drop-shadow on textVery high on mobile GPUs18 to 30 fps plus heatNever loop, static only
Three simultaneous full-width loopsMultiplied paint plus composite30 to 35 fps with scroll jankCap to one per viewport

Choppy-animation diagnosis when shine stutters

When shine stutters, I diagnose in order. First I check if I animated an expensive property. Second I check layer count. Third I check size and weight. Fourth I check output classes. Fifth I check Safari with the full prefix pair from the generator.

Next steps to L1 plus Tailwind guide

If this L2 gave you smooth motion, go back to the parent L1 CSS Gradient Text Generator Guide to lock stops, angle, contrast at 4.5 to 1 for body plus 3 to 1 for large bold, prefixes, and PNG plus SVG export. Then branch to the Tailwind gradient text guide to tokenize winners so rebrands edit one line.

Verdict from my testing: Live clipped preview, position-based shine, hover gating, reduced-motion static fallback, prefix safety, and one loop per viewport discipline. Start with Ocean at 90 degrees 72px 800 weight sliding 0 to 200 percent in 6s, test lightest stop, then branch once the smooth base is locked.