Learn how to define typed CSS custom properties using @property to enable smooth animations and provide fallback values.
What it is
The @property at-rule allows you to register a custom property with specific metadata, including its syntax type, initial value, and inheritance behavior. Unlike standard custom properties (e.g., --my-var: 10px), which are treated as untyped strings by the browser, registered properties are parsed according to their defined syntax. This enables the browser to understand that a value like 45deg is an angle, allowing for interpolation during transitions and animations.
Mental Model: Think of standard custom properties as generic text boxes where anything goes. Registered properties via @property are like typed input fields in a form; they enforce rules about what data can be entered and how it should be processed.
Related terms: Custom Properties, CSS Variables, Interpolation, Initial Value.
Why it matters
- Animatable Values: Standard variables cannot be animated smoothly because the browser sees them as discrete strings. Typed properties allow smooth transitions between numeric or color values.
- Fallbacks: You can define an
initial-value, ensuring the variable has a valid state even if not explicitly set in the style sheet. - Inheritance Control: You can explicitly declare whether a property inherits from parent elements (
inherits: true) or remains local (inherits: false). - Validation: The browser validates values against the specified
syntax, helping catch errors early.
Syntax or steps
To use @property, you must define the rule before using the variable in your styles. The basic structure requires three descriptors:
syntax: A string defining the allowed format (e.g.,'<angle>','<color>','*').initial-value: The default value used if none is provided.inherits: A boolean indicating if the property cascades down the DOM tree.
Example
/* 1. Register the property */
@property --rotation {
syntax: '<angle>';
initial-value: 0deg;
inherits: false;
}
/* 2. Use the property in animation */
.spinner {
width: 50px;
height: 50px;
border: 5px solid #333;
border-top-color: #007bff;
border-radius: 50%;
/* Apply the variable to transform */
transform: rotate(var(--rotation));
/* Animate the variable itself */
animation: spin 2s linear infinite;
}
@keyframes spin {
to {
--rotation: 360deg;
}
}
Explanation:
- The
@propertyblock tells the browser that--rotationis strictly an angle starting at0deg. - In the
.spinnerclass, we applytransform: rotate(var(--rotation)). - The
@keyframesrule changes--rotationto360deg. Because the property is typed, the browser interpolates the angle smoothly from 0 to 360 degrees, creating a continuous rotation effect.
Common mistakes
- Missing Quotes in Syntax: Writing
syntax: <angle>instead ofsyntax: '<angle>'. The syntax descriptor requires a quoted string. - Invalid Initial Value: Setting
initial-value: 0when the syntax is'<angle>'. It must be0degto match the type. - Forgetting Inheritance: If you want a global theme color to cascade, you must set
inherits: true. Defaulting tofalsemight break expected behavior. - Using Untyped Animations: Trying to animate a standard variable without registering it first will result in a jump rather than a smooth transition.
When to use it
| Feature | Standard Custom Property | Registered Property (@property) |
|---|---|---|
| Animation Support | No (jumps between values) | Yes (smooth interpolation) |
| Default Value | Must be set manually or via fallback | Built-in initial-value |
| Type Safety | None (string only) | Enforced by syntax |
| Best For | Static colors, spacing, simple toggles | Gradients, rotations, complex transitions |
Practice
Guided Exercise: Create a button that changes its background color from blue to red on hover using a registered property named --bg-color.
Challenge: Modify the example above to create a conic gradient loader. Hint: Use syntax: '<percentage>' for a stop position variable.
Quick check
Q: Why does animating a standard CSS variable usually fail to produce smooth motion?
A: Standard variables are treated as opaque strings. The browser cannot mathematically interpolate between two different strings (like "red" and "blue") unless they are registered as typed properties (like <color>).
Summary
The @property rule transforms CSS variables from static placeholders into dynamic, typed entities. By defining syntax and initial values, you unlock native browser support for smooth animations and robust defaults, making complex interactive designs easier to maintain.