Summary

  • The W3C’s first CSS Properties and Values API draft in June 2016 proposed registering a custom property through JavaScript with a value type, initial value and inheritance behavior; its color-stop example used that type to animate a gradient smoothly.
  • A 2019 draft added the CSS @property route. The 2024 draft explained computed-value checking, the descriptors a registration needs and the document-wide consequences of giving one custom name a shared meaning.

The designer has two color swatches: red and green. She wants the stop in a gradient to travel between them over a second, rather than jump as if somebody changed the slide. A custom property named --stop-color looks like the obvious messenger. It can carry the swatches. But the browser cannot interpolate an arbitrary bag of CSS tokens as a color merely because its name contains the word “color.” At the job interview, the variable has a suitcase full of values and no line on its résumé saying what they are.

The W3C’s first public CSS Properties and Values API draft, 7 June 2016, supplied that line through registration. Its stated purpose was to extend CSS Variables so a custom property could declare a value type, an initial value and whether it inherits. The draft’s method was CSS.registerProperty() in JavaScript. Its example registered --stop-color with a <color> syntax, an initial transparent color and inherits: false, then changed the value on hover while transitioning the property. Once the browser knew it was dealing with colors, the red-to-green trip could have intermediate stops. The name alone had never done that work.

The 9 November 2017 Working Draft kept developing that registered-property model. This chapter of the history still spoke through the JavaScript API. That distinction matters because the familiar CSS @property block had not yet arrived in those captured drafts. The early idea was a contract with the browser about a custom value; the later argument was also about where an author should be able to write the contract.

By the 25 October 2019 draft, there were two doors: CSS.registerProperty() in script and @property in a stylesheet. The CSS rule could declare syntax, inherits and initial-value beside the styles that used the name. This made registration visible to someone reading the CSS itself. A designer could meet --radius near the circle it controlled and see that it was a length, began at zero and did not inherit. The browser received a typed value; the publisher kept the decision about what visual change the value should drive.

The 13 October 2020 draft continued both routes and the animation examples. The concrete payoff was interpolation with rules. A color can move through other colors. A length can move between sizes. With a registered --radius, a painted circle can grow from ten pixels to fifty through the in-between sizes instead of teleporting from small to large. The browser has something meaningful to calculate at each frame.

The 26 March 2024 draft shows how much work hides behind that pleasant ribbon of motion. A valid @property rule needs a syntax and an inherits descriptor. When the syntax is a specific type rather than the universal *, it also needs a valid, computationally independent initial-value. These are the answers at the interview: what values are allowed, what happens before a value is supplied, and whether children receive it by default. Leave a required answer blank and the registration itself is ignored. A value such as --radius can then be treated as a length rather than as a mysterious parcel.

The same draft contains a less visible surprise. The type is checked at computed-value time, not when the stylesheet is first read. A script or another stylesheet can register a name after a declaration was parsed. If the browser had thrown away every value that failed an as-yet-unknown type at parse time, it could not recover the declaration when the type appeared later. The specification explains the cost of the alternatives: keep every discarded declaration or parse the whole sheet again. Registration gives values a type, but the browser waits for the right stage of its work to enforce it.

Even the job interview has to happen at the correct desk.

Names have another consequence. The 2024 text describes registrations as shared across a document, including registrations written inside Shadow DOM. If several valid @property rules use the same name, the last one in stylesheet order wins; a JavaScript registration for that name takes precedence over the rules. A component author who thinks a private shadow tree guarantees a private meaning for --radius may find that the name belongs to the larger document. The CSS Working Group recorded both sides of the problem: components want local room, while values sent into them from outside need a type that both sides understand. The browser cannot interpolate a name according to two contradictory contracts at once.

The W3C publication history dates the journey from the 2016 first public draft through the 2017, 2019, 2020 and 2024 revisions. Read that way, @property is the visible form of an older question: what must an author tell the browser so a custom value can participate in the ordinary machinery of CSS? The answer is a small declaration of type, starting point and inheritance. The reward is a gradient that walks from red to green instead of changing its mind in one frame.