← Back to CSS Course | Chapter 9: Modern CSS Features | Lesson 13 of 25

CSS @property

Think of a plain sticky note that just says 10 with no context -- is that dollars, degrees, or a page number? Now imagine a smart label maker that stamps 'THIS IS A NUMBER, DEFAULT 0, DO NOT INHERIT' right onto the note. @property is that label maker for CSS custom properties: it gives a --variable a real, enforced type instead of leaving it as untyped text.

The Problem With Plain Custom Properties

A plain --custom-property declared with var() has no type checking at all -- the browser treats its value as an opaque string substituted at use-time, which means it can't be smoothly animated (the browser doesn't know how to interpolate between two arbitrary strings) and typos or invalid values fail silently.

Example: The Problem With Plain Custom Properties

css
:root {
  --my-color: red;
}
.box {
  transition: --my-color 0.3s;
}

Registering a Typed Property With @property

@property registers a custom property name with an explicit syntax (its type, like <length> or <color>), whether it inherits, and an initial-value -- turning what was an opaque string into a real, browser-understood typed value.

Example: Registering a Typed Property With @property

css
@property --my-color {
  syntax: '<color>';
  inherits: false;
  initial-value: red;
}

The syntax Descriptor

The syntax descriptor declares the accepted value type using predefined syntax component names like <color>, <length>, <percentage>, <number>, or <angle> -- an invalid value assigned to the property is rejected and the initial-value is used instead, unlike plain custom properties which accept anything.

Example: The syntax Descriptor

css
@property --gap-size {
  syntax: '<length>';
  inherits: false;
  initial-value: 0px;
}

Now It Can Be Smoothly Animated

Because a registered property has a real, interpolatable type, the browser can now animate it smoothly with transition or @keyframes -- this is the primary practical payoff of @property, unlocking animations that were impossible with a plain untyped custom property.

Example: Now It Can Be Smoothly Animated

css
<style>
@property --angle {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}
.box {
  background: conic-gradient(red var(--angle), blue);
  transition: --angle 0.3s;
}
.box:hover {
  --angle: 180deg;
}
</style>
<div class="box">Now smoothly animatable</div>

The inherits and initial-value Descriptors

inherits (true/false) explicitly controls whether the property flows down to child elements, and initial-value sets the fallback used whenever the property is unset or assigned an invalid value -- both descriptors are required for a valid @property rule, unlike the optional nature of plain custom property fallbacks in var().

Example: The inherits and initial-value Descriptors

css
@property --my-size {
  syntax: '<length>';
  inherits: true;
  initial-value: 16px;
}

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.