@property Builder

CSS custom properties (variables) became powerful in 2018, but they had one major limitation: you couldn't animate them smoothly. The browser didn't know what type of value they held, so transitions between, say, two colors stored in variables would just snap. The @property at-rule fixes this. By declaring a syntax type, you tell the browser 'this variable holds a color' (or length, or angle), and suddenly transitions and animations work as expected. This builder generates valid @property declarations and shows you the resulting animation behavior in real-time.

Hover me

What is @property?

The CSS @property at-rule lets you explicitly register custom properties with a defined syntax type, inheritance behavior, and initial value. Before @property, custom properties were opaque strings to the browser — it couldn't distinguish a color from a length, so it had no way to interpolate intermediate values during transitions or animations. By declaring a syntax like <color> or <length>, you give the browser the type information it needs to compute smooth in-between values. This also enables better fallback handling: if a value doesn't match the declared syntax, the browser falls back to the initial-value instead of producing an invalid state.

The @property rule is part of the CSS Properties and Values API, which originated from the CSS Houdini project. It provides a declarative CSS alternative to the JavaScript CSS.registerProperty() method. Each @property declaration includes three required descriptors: syntax, which defines the type of value the property accepts; inherits, which controls whether the property value is inherited by child elements; and initial-value, which sets the default value used when no other value is assigned or when an invalid value is provided. Together, these descriptors transform a basic custom property into a fully typed CSS value that the browser can reason about at a much deeper level.

One of the most powerful applications of @property is enabling gradient animations. Normally, CSS gradients cannot be smoothly transitioned because the browser treats the entire gradient as an image, and there is no interpolation defined between two images. However, by registering a custom property with a specific type — such as <angle> for a gradient direction or <color> for a gradient stop — you can animate the individual parts of a gradient declaration. This opens up a wide range of visual effects that were previously impossible without JavaScript, including rotating conic gradients, pulsing color stops, and smoothly shifting gradient hues.

How to use this tool

Start by entering your custom property name (it must begin with two dashes, like --my-color). Choose a syntax type from the dropdown that matches the kind of value your property will hold. Toggle the inherits checkbox to control whether child elements inherit this property's value from their parent. Set an initial value that matches your chosen syntax — for color types, you can use the color picker for convenience. The preview box immediately demonstrates the animation behavior: hover over it to see the smooth transition that @property enables. Copy the Direct CSS output for a ready-to-use transition example, or the CSS Variables output for a keyframe animation version.

When choosing a syntax type, consider what kind of animation you need. Use <color> for background and text color transitions, <length> for spacing and sizing animations, <angle> for rotating gradients or transforms, <number> for opacity-like values, and <percentage> for responsive scaling effects. If your property needs to accept any value without type checking, select the * (universal) syntax — but note that universal syntax properties cannot be animated because the browser still cannot infer the interpolation method.

Practical examples

Animating a gradient angle using @property

This example registers a custom property with <angle> syntax so you can smoothly rotate a conic gradient. Without @property, changing the gradient angle would cause a hard snap between values.

@property --gradient-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.gradient-spinner {
  --gradient-angle: 0deg;
  background: conic-gradient(
    from var(--gradient-angle),
    #7c9eff,
    #4ade80,
    #7c9eff
  );
  animation: spin-gradient 3s linear infinite;
}

@keyframes spin-gradient {
  to {
    --gradient-angle: 360deg;
  }
}

Creating a typed color property for smooth color transitions

Register a color property so that changing it via a class toggle or hover produces a smooth interpolation through the color space instead of a hard swap.

@property --card-bg {
  syntax: "<color>";
  inherits: false;
  initial-value: #1a1a2e;
}

.card {
  background: var(--card-bg);
  transition: --card-bg 0.4s ease;
}

.card:hover {
  --card-bg: #16213e;
}

.card.active {
  --card-bg: #0f3460;
}

Using @property for a responsive spacing scale

A registered <length> property can be animated or transitioned, making layout shifts feel smooth when the spacing scale changes (for example, switching between compact and comfortable density modes).

@property --spacing-unit {
  syntax: "<length>";
  inherits: true;
  initial-value: 16px;
}

:root {
  --spacing-unit: 16px;
  transition: --spacing-unit 0.3s ease;
}

:root.compact {
  --spacing-unit: 8px;
}

.stack > * + * {
  margin-top: var(--spacing-unit);
}

.card {
  padding: var(--spacing-unit);
}

Common patterns and best practices

When working with @property, follow these guidelines to get the most out of typed custom properties:

Browser support

The @property at-rule is supported in all major browsers since mid-2024. Chrome was the first to ship support in version 85 (July 2020). Safari added support in version 16.4 (March 2023). Firefox, which was the last holdout, shipped support in version 128 (July 2024). This means @property is now safe to use in production for all modern browsers without polyfills or fallbacks.

For older browser support, you can use the JavaScript equivalent CSS.registerProperty(), which provides the same functionality programmatically. Alternatively, provide a non-animated fallback by setting the custom property as a regular unregistered variable. The @property declaration will simply be ignored by unsupported browsers, and the property will behave as a standard custom property without animation capability.

FAQ

Why can't I just animate regular CSS variables?

Regular CSS custom properties are treated as opaque strings by the browser. When you transition from --color: red to --color: blue, the browser doesn't know these are colors — it sees two arbitrary strings and has no way to calculate intermediate values. It simply swaps one for the other at the halfway point, causing a hard snap. The @property rule solves this by declaring the syntax type (e.g., <color>), which gives the browser the information it needs to interpolate smoothly between values during transitions and animations.

What happens if my variable value doesn't match the syntax?

When you register a custom property with @property and assign a value that doesn't match the declared syntax, the browser discards the invalid value and falls back to the initial-value you specified in the @property declaration. This is a significant advantage over unregistered custom properties, where an invalid value would simply be passed through and likely cause layout issues. The type checking acts as a safety net, ensuring your property always holds a valid, usable value.

Which syntax types does @property support?

The supported syntax types include <length>, <number>, <percentage>, <color>, <angle>, <time>, <resolution>, <transform-function>, <custom-ident>, and combinations using the + (space-separated list) and # (comma-separated list) multipliers, plus the * universal syntax.

Does @property work with the cascade?

Yes, @property registered properties participate fully in the cascade and inheritance. The inherits descriptor controls whether the property is inherited by child elements. When inherits is set to true, the property value cascades down the DOM tree just like built-in inherited properties such as color or font-size. When set to false, each element uses either its own explicitly set value or the initial-value from the registration.

Can I register the same property with both @property and CSS.registerProperty()?

The first registration wins. If @property is declared in CSS, a subsequent JavaScript CSS.registerProperty() call for the same property will be ignored. The reverse is also true — if CSS.registerProperty() runs before the stylesheet is parsed, the CSS @property declaration is ignored. In practice, it is best to pick one registration method and use it consistently throughout your project.

What happens if I don't set initial-value?

The initial-value descriptor is required for all syntax types except * (universal syntax). If omitted with a typed syntax, the @property rule is invalid and will be ignored by the browser entirely. For the universal * syntax, omitting initial-value is allowed because the browser cannot validate any specific type, and the property simply has no default value until one is set explicitly.

Related tools