Seven ways to animate gradients: an angle that turns, colour stops that morph, a mesh whose centres drift, stripes moving along a progress bar, a hue rotation, a gradient border that flows round a card and a metallic sheen across a word.
A linear gradient whose angle turns slowly through 360 degrees. Without @property the browser cannot interpolate the angle inside a gradient, so the angle is registered as an <angle> custom property and that property is animated.
Two registered colour properties feed a gradient, and animating them makes the colours themselves change, not just their position. This is the only way to smoothly morph a gradient's colours in CSS.
View code
<div class="ga2" role="img" aria-label="Gradient changing from teal and blue to orange and pink"></div>
Three radial gradients whose centres drift on slightly different loops, a living mesh behind a hero. The centre coordinates are registered percentage properties, so each one interpolates smoothly while the others move on their own timings.
Diagonal stripes travel along a progress bar to show work is ongoing. The stripes are a repeating linear gradient whose background-position moves by exactly one stripe period, so the loop is seamless. The bar is a labelled progressbar with its value.
The simplest colour cycle: one gradient and filter: hue-rotate animating from 0 to 360 degrees, which shifts every colour around the wheel together. It also affects any content inside, so keep text outside the filtered layer, as here.
A card whose border is a gradient flowing round it, done with two backgrounds: the card colour clipped to the padding box and an oversized gradient clipped to the border box, moved with background-position.
A metallic sheen sweeps across a word every few seconds: a gradient clipped to the text, mostly one colour with a bright band, moving with background-position. Outside the sweep it rests on solid dark text that is easy to read.
A gradient is an image, and browsers cannot interpolate one image into another. Change something they can interpolate instead: the background position, a filter, or a registered custom property used inside the gradient.
@property unlocks gradients
Register an angle, colour or percentage with @property and give it a syntax. The browser can then animate the property, and the gradient that uses it updates on every frame.
Seamless loops
For moving stripes or patterns, move the background by exactly one repeat of the pattern so the end frame matches the start. For diagonal stripes that repeat is the stripe period divided by the sine of the angle.
Keep text off the moving layer
Effects like hue-rotate apply to everything inside the element. Put the animated gradient on its own layer and the text above it on a solid backing for contrast.
Frequently asked questions
Which browsers support @property?
All current major browsers. Older ones show the gradient without animating it.
Are animated gradients heavy?
Repainting a large gradient every frame costs more than moving it. Keep animated areas modest.
Can I animate a gradient border?
Yes, with two backgrounds, one clipped to the padding box and one to the border box, as the border demo shows.