@property
The Problem
Standard CSS custom properties are untyped — the browser treats them as arbitrary strings. This means you cannot animate or transition custom properties (e.g., smoothly transitioning a gradient), the browser cannot validate their values, and inheritance behavior cannot be controlled. AI agents rarely use @property and instead resort to JavaScript animations or complex workarounds for effects that @property makes trivial.
The Solution
The @property at-rule lets you formally register a CSS custom property with a type (syntax), an initial value, and inheritance control. Once a property is typed, the browser can interpolate it — enabling smooth transitions and animations on values that were previously impossible to animate, like gradients, colors within gradients, and individual numeric values.
Code Examples
Basic @property Declaration
@property --primary-color {
syntax: "<color>";
inherits: true;
initial-value: #2563eb;
}
@property --card-radius {
syntax: "<length>";
inherits: false;
initial-value: 8px;
}
@property --opacity-level {
syntax: "<number>";
inherits: false;
initial-value: 1;
}
Animating Gradients
Without @property, gradient transitions snap between states. With typed properties, smooth interpolation becomes possible.
@property --gradient-start {
syntax: "<color>";
inherits: false;
initial-value: #3b82f6;
}
@property --gradient-end {
syntax: "<color>";
inherits: false;
initial-value: #8b5cf6;
}
.hero-banner {
background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end));
transition: --gradient-start 0.6s, --gradient-end 0.6s;
}
.hero-banner:hover {
--gradient-start: #ec4899;
--gradient-end: #f59e0b;
}
Animated Gradient Angle
@property --angle {
syntax: "<angle>";
inherits: false;
initial-value: 0deg;
}
.rotating-gradient {
background: linear-gradient(var(--angle), #3b82f6, #8b5cf6);
animation: rotate-gradient 3s linear infinite;
}
@keyframes rotate-gradient {
to {
--angle: 360deg;
}
}
Progress Indicator with Animated Percentage
@property --progress {
syntax: "<percentage>";
inherits: false;
initial-value: 0%;
}
.progress-ring {
background: conic-gradient(
#2563eb var(--progress),
#e5e7eb var(--progress)
);
border-radius: 50%;
transition: --progress 1s ease-out;
}
.progress-ring[data-value="75"] {
--progress: 75%;
}
Type-Safe Design Tokens
@property --spacing-unit {
syntax: "<length>";
inherits: true;
initial-value: 0.25rem;
}
@property --brand-hue {
syntax: "<number>";
inherits: true;
initial-value: 220;
}
.design-system {
--spacing-unit: 0.25rem;
--brand-hue: 220;
}
.card {
padding: calc(var(--spacing-unit) * 4);
background: hsl(var(--brand-hue) 90% 95%);
border: 1px solid hsl(var(--brand-hue) 60% 70%);
}
Controlling Inheritance
@property --section-bg {
syntax: "<color>";
inherits: false; /* Does NOT cascade to children */
initial-value: transparent;
}
.section {
--section-bg: #f0f9ff;
background: var(--section-bg);
}
/* Nested sections get transparent (initial-value), not the parent's blue */
.section .section {
/* --section-bg is transparent here because inherits: false */
background: var(--section-bg);
}
Supported Syntax Types
/* All supported syntax descriptors */
@property --a { syntax: "<color>"; inherits: false; initial-value: black; }
@property --b { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --c { syntax: "<percentage>"; inherits: false; initial-value: 0%; }
@property --d { syntax: "<number>"; inherits: false; initial-value: 0; }
@property --e { syntax: "<integer>"; inherits: false; initial-value: 0; }
@property --f { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
@property --g { syntax: "<time>"; inherits: false; initial-value: 0s; }
@property --h { syntax: "<resolution>"; inherits: false; initial-value: 1dppx; }
@property --i { syntax: "<length-percentage>"; inherits: false; initial-value: 0px; }
@property --j { syntax: "<image>"; inherits: false; initial-value: url(); }
@property --k { syntax: "<transform-function>"; inherits: false; initial-value: scale(1); }
@property --l { syntax: "<custom-ident>"; inherits: false; initial-value: none; }
/* Union types */
@property --m { syntax: "<color> | <length>"; inherits: false; initial-value: black; }
/* Universal (any value, like regular custom properties) */
@property --n { syntax: "*"; inherits: true; }
Browser Support
- Chrome 85+
- Edge 85+
- Firefox 128+
- Safari 15.4+
Global support exceeds 93%. Firefox added support in mid-2024, making @property available in all major browsers. The feature is Baseline Newly available as of July 2024.
Common AI Mistakes
- Not using
@propertywhen trying to animate gradients or custom property values — resulting in abrupt snapping instead of smooth transitions - Using JavaScript-based animation (requestAnimationFrame) for effects that typed custom properties handle natively
- Forgetting that all three descriptors (
syntax,inherits,initial-value) are required (exceptinitial-valuewhensyntaxis*) - Setting
inherits: truewhen the property should be component-scoped, causing unintended cascade leakage - Not knowing that
@propertyenables gradient animations — this is the most impactful and most overlooked use case - Confusing
@propertyregistration with the JavaScriptCSS.registerProperty()API — the CSS at-rule is preferred for static definitions
When to Use
- Smooth gradient transitions and animations (the primary killer use case)
- Animated progress indicators, loading spinners, and visual effects using conic/radial gradients
- Type-safe design tokens where the browser should validate property values
- Controlling inheritance to prevent custom properties from cascading into nested components
- Any animation that requires interpolating a custom property value