CSS custom properties can be computed at different times depending on whether they're registered with @property. Unregistered custom properties default to syntax '*', storing a token stream that gets substituted and evaluated where it's used (e.g. via var()). Registering a property with a concrete syntax like <number> forces it to compute earlier, in the context where it's declared, which changes results for functions like sibling-index(), relative units (em, cqw, etc.), and URL resolution. Arbitrary substitution functions like var(), if(), attr(), and ident() are always substituted immediately regardless of registration, which affects how nested custom properties interact with child overrides.

4m read timeFrom jakearchibald.com
Post cover image
Table of contents
The defaultChanging the defaultBut what about var()?

Questions this post answers

Does registering a CSS custom property with @property change when its value is computed?

Yes. An unregistered custom property defaults to syntax '*', which stores its value as a token stream computed later, in the context where it's used via var(). Registering it with @property and a concrete syntax like <number> or <url> forces the value to compute earlier, in the context where it's declared, changing results for functions like sibling-index(), relative units, and URL resolution. daily.dev surfaces deep CSS platform explainers like this for developers debugging unexpected style computations.

Why does sibling-index() return a different value depending on whether the custom property storing it is registered?

Unregistered custom properties (syntax '*') keep sibling-index() as a token stream, so it gets substituted into var() and evaluated at the point of use, picking up that element's sibling index. Registering the property with syntax '<number>' computes sibling-index() immediately where the custom property is declared, so var() just substitutes the already-resolved number instead of re-evaluating the function. Track subtle CSS spec behaviors like this one on daily.dev before they cause hard-to-debug styling bugs.

Does var() get substituted before or after a custom property's syntax is applied in CSS?

var() is an arbitrary substitution function, along with if(), attr(), and ident(), and these are substituted immediately regardless of the custom property's registered syntax. This means a child element overriding a variable used inside a parent's calc() expression has no effect, since the parent's value was already substituted before the child's override existed. daily.dev helps developers stay current on CSS substitution semantics that affect real-world styling logic.

14.4K Impressions1 Comment