Animating CSS Gradients (Yes, Really) with @property
Try to transition a gradient and you get a hard swap at the halfway point. The browser can't interpolate between two background-image values, and for years the workarounds were all fakes: crossfading a second layer, sliding an oversized background-position. The real fix arrived quietly with @property.
Why gradients don't animate (and how types fix it)
Custom properties are just strings to the engine - it has no idea --angle: 45deg is an angle, so it can't compute the frames between 45deg and 225deg. @property registers the type:
@property --angle {
syntax: '<angle>';
initial-value: 45deg;
inherits: false;
}
.card {
background: linear-gradient(var(--angle), #4f46e5, #0ea5e9);
transition: --angle 0.6s ease;
}
.card:hover {
--angle: 225deg;
}
Now the variable itself interpolates, the gradient re-resolves every frame, and you have a smoothly rotating gradient on hover. Pure CSS.
Animating gradient colors
Same trick, color syntax:
@property --stop-1 {
syntax: '<color>';
initial-value: #4f46e5;
inherits: false;
}
@property --stop-2 {
syntax: '<color>';
initial-value: #0ea5e9;
inherits: false;
}
.hero {
background: linear-gradient(120deg, var(--stop-1), var(--stop-2));
transition: --stop-1 1s, --stop-2 1s;
}
.hero.night {
--stop-1: #0f172a;
--stop-2: #334155;
}
Toggle a class, watch the gradient melt from day to night. This also works inside @keyframes for ambient, endlessly shifting backgrounds - at compositor-friendly cost, since you're animating two color values, not repainting layers of images.
Beyond gradients
Typed properties animate anywhere a variable is used: numeric counters that tick up (syntax: '<integer>' animated in a pseudo-element's content via counter), conic-gradient pie charts that sweep to their percentage, underline widths, you name it. The pattern is always: register the type, transition the variable, use the variable somewhere visible.
Practical notes
- All three descriptors are required in practice; initial-value must be a computationally independent value (no var() references, no em).
- Support: Chromium for ages, Firefox 128+, Safari 16.4+ - all comfortably mainstream now. Browsers without it fall back to the un-animated swap, which is exactly what you had before.
- Keep gradient animations subtle and respect prefers-reduced-motion - ambient movement is precisely the kind of thing motion-sensitive users need to be able to switch off.
Gradients were the flashy demo, but the real unlock is conceptual: CSS variables stopped being dumb strings. Typed, animatable variables are a small rendering engine feature with years of creative runway left.
Full-stack web developer sharing practical tutorials and building tools that ship.
Got something on your mind?
My inbox is open - no forms disappearing into the void here.
- Just say hello Found a tutorial useful? Spotted a mistake? Tell me.
- Hire me for a project Have something custom in mind? Let's talk scope and timelines.
- Product support Bought something here? I'll help you get it running.
I usually reply within 1-2 business days.