← all topics

CSS Custom Properties

CSS

Without @property, the browser treats custom properties as opaque strings — they can't be interpolated. Registering a property with a syntax type unlocks smooth transitions between values.

no @property
flickers

The browser cannot interpolate the background shorthand — it jumps between keyframes with no smooth transition.

with @property
smooth

--hue-start is a registered <number> — the browser interpolates it like any numeric value.

Controls
220°
80%

@property --hue-start {
syntax: '<number>';
inherits: false;
initial-value: 220;
}

concepts

unregistered props are strings

The browser treats --hue: 220 as an opaque string. It can't interpolate "220" → "580" — so animating it causes a jump rather than a smooth transition.

@property registration

Declares a syntax type for a custom property, giving the browser the type information it needs to interpolate values just like built-in CSS properties.

inherits: false

Prevents the property from cascading down to child elements, avoiding unexpected color inheritance from ancestor elements that also use the property.

the trick

Gradient colors use hsl(var(--hue), ...). When --hue is a registered <number>, the browser smoothly tweens the number — the gradient color changes as a side effect.

core pattern

@property --hue {
  syntax: '<number>';   /* typed — browser can interpolate */
  inherits: false;
  initial-value: 220;
}

@keyframes spin {
  from { --hue: 220; }
  to   { --hue: 580; }  /* browser interpolates 220→580 */
}

.box {
  background: linear-gradient(135deg,
    hsl(var(--hue), 80%, 60%),
    hsl(calc(var(--hue) + 120), 80%, 60%)
  );
  animation: spin 2s ease-in-out infinite alternate;
}