CSS @property: Finally Animating the Un-animatable
Declare custom property types with @property to unlock gradient, color, and numeric animations
CSS custom properties (variables) can't animate by default. Set --color
from red to blue, and it jumps instantly—no transition. The @property
rule changes this by declaring the variable's type, enabling smooth interpolation.
Why Variables Don't Animate
CSS custom properties are strings. The browser doesn't know if --foo: 10
is a number, length, angle, or just text. Without type information, interpolation
is impossible—how do you animate between "red" and "blue"
as strings?
:root {
--bg-color: red;
transition: --bg-color 0.5s; /* Does nothing! */
}
.element {
background: var(--bg-color);
}
:root:hover {
--bg-color: blue; /* Instant jump, no transition */
}@property: Typed Custom Properties
The @property rule registers a custom property with explicit type
information. The browser can now interpolate values:
@property --bg-color {
syntax: '<color>';
inherits: false;
initial-value: red;
}
.element {
background: var(--bg-color);
transition: --bg-color 0.5s;
}
.element:hover {
--bg-color: blue; /* Smooth transition! */
}
The syntax descriptor tells the browser this is a color. Now it
knows to interpolate through color space, just like background-color
would.
Available Syntax Types
<color>— any valid CSS color<length>— px, rem, em, etc.<percentage>— 0% to 100%<number>— unitless numbers<integer>— whole numbers only<angle>— deg, rad, turn<length-percentage>— length or percentage<transform-function>— rotate(), scale(), etc.<custom-ident>— keyword identifiers*— any value (default, no interpolation)
The Killer Use Case: Gradient Animation
background: linear-gradient() can't animate—the gradient is a single
computed image. But you can animate the values inside the gradient:
@property --gradient-angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
@property --gradient-start {
syntax: '<color>';
inherits: false;
initial-value: #ff6b6b;
}
@property --gradient-end {
syntax: '<color>';
inherits: false;
initial-value: #4ecdc4;
}
.gradient-box {
background: linear-gradient(
var(--gradient-angle),
var(--gradient-start),
var(--gradient-end)
);
transition:
--gradient-angle 1s,
--gradient-start 1s,
--gradient-end 1s;
}
.gradient-box:hover {
--gradient-angle: 180deg;
--gradient-start: #a8e6cf;
--gradient-end: #fdcb6e;
}The gradient itself doesn't transition—but each custom property inside it does, creating the effect of an animating gradient.
Animating with @keyframes
Typed properties work with keyframe animations too:
@property --hue {
syntax: '<number>';
inherits: false;
initial-value: 0;
}
@keyframes rainbow {
to {
--hue: 360;
}
}
.rainbow-text {
color: hsl(var(--hue), 80%, 50%);
animation: rainbow 5s linear infinite;
}Required Descriptors
All three descriptors are mandatory:
@property --my-prop {
syntax: '<length>'; /* Required: the type */
inherits: true; /* Required: does it inherit? */
initial-value: 0px; /* Required: default value */
}
inherits controls whether child elements inherit the property.
For animation purposes, false is usually what you want—each element
manages its own value.
Browser Support Caveat
@property works in all modern browsers (Chrome 85+, Firefox 128+,
Safari 15.4+). For older browsers, the animation simply won't happen—the property
falls back to instant changes. This is progressive enhancement at its best.
/* Fallback: still works, just no animation */
:root {
--accent: blue;
}
/* Enhancement: animates in supporting browsers */
@property --accent {
syntax: '<color>';
inherits: false;
initial-value: blue;
}JavaScript Registration Alternative
You can also register properties via JavaScript with CSS.registerProperty():
CSS.registerProperty({
name: '--my-color',
syntax: '<color>',
inherits: false,
initialValue: 'red'
});
// Useful for dynamic registration
// Same capabilities as @propertyThis is part of the CSS Houdini specification. Use it when you need runtime registration or when generating property names dynamically.
The Takeaway
@property turns custom properties from dumb strings into typed,
animatable values. Gradients, complex color schemes, numeric values—anything
that couldn't transition before can now animate smoothly. It's one of the most
powerful CSS features you're probably not using yet.
Advertisement
Explore these curated resources to deepen your understanding
Official Documentation
Tools & Utilities
Related Insights
Explore related edge cases and patterns
Advertisement