@property: giving superpowers to CSS variables
The Houdini Properties and Values API is coming to your CSS file in Chromium 85.
CSS Houdini is an umbrella term that covers a set of low-level APIs that expose parts of the CSS rendering engine, and give developers access to the CSS Object Model. This is a huge change for the CSS ecosystem, as it enables developers to tell the browser how to read and parse custom CSS without waiting for browser vendors to provide built-in support for these features. So exciting!
One of the most exciting additions to CSS within the Houdini umbrella is the Properties and Values API.
This API supercharges your CSS custom properties (also commonly referred to as CSS variables) by giving them semantic meaning (defined by a syntax) and even fallback values, enabling CSS testing.
- Chrome 78, Supported 78
- Firefox, Not supported
- Edge 79, Supported 79
- Safari 16.4, Supported 16.4
Writing Houdini custom properties #
Here's an example of setting a custom property (think: CSS variable), but now with a syntax (type), initial value (fallback), and inheritance boolean (does it inherit the value from it's parent or not?). The current way to do this is through CSS.registerProperty()
in JavaScript, but in Chromium 85 and later, the @property
syntax will be supported in your CSS files:
Separate JavaScript file (Chromium 78)
CSS.registerProperty({
name: '--colorPrimary',
syntax: '<color>',
initialValue: 'magenta',
inherits: false
});
Included in CSS file (Chromium 85)
@property --colorPrimary {
syntax: '<color>';
initial-value: magenta;
inherits: false;
}
Now you can access --colorPrimary
like any other CSS custom property, via var(--colorPrimary)
. However, the difference here is that --colorPrimary
isn't just read as a string. It has data!
Fallback values #
As with any other custom property, you can get (using var) or set (write/rewrite) values, but with Houdini custom properties, if you set a falsey value when overriding it, the CSS rendering engine will send the initial value (its fallback value) instead of ignoring the line.
Consider the example below. The --colorPrimary
variable has an initial-value
of magenta
. But the developer has given it the invalid value "23". Without @property
, the CSS parser would ignore the invalid code. Now, the parser falls back to magenta
. This allows for true fallbacks and testing within CSS. Neat!
.card {
background-color: var(--colorPrimary); /* magenta */
}
.highlight-card {
--colorPrimary: yellow;
background-color: var(--colorPrimary); /* yellow */
}
.another-card {
--colorPrimary: 23;
background-color: var(--colorPrimary); /* magenta */
}
Syntax #
With the syntax feature, you can now write semantic CSS by specifying a type. The current types that are allowed include:
length
number
percentage
length-percentage
color
image
url
integer
angle
time
resolution
transform-list
transform-function
custom-ident
(a custom identifier string)
Setting a syntax enables the browser to type-check custom properties. This has many benefits.
To illustrate this point, I'll show you how to animate a gradient. Currently, there is no way to smoothly animate (or interpolate) between gradient values, as each gradient declaration is parsed as a string.
In this example, the gradient stop percentage is being animated from a starting value of 40% to an ending value of 100% via a hover interaction. You should see a smooth transition of that top gradient color downward.
The browser on the left supports the Houdini Properties and Values API, enabling a smooth gradient stop transition. The browser on the right does not. The non-supporting browser is only able to understand this change as a string going from point A to point B. There is no opportunity to interpolate the values, and thus you don't see that smooth transition.
However, if you declare syntax type when writing custom properties, and then use those custom properties to enable the animation, you'll see the transition. You can instantiate the custom property --gradPoint
like so:
/* Check for Houdini support & register property */
@supports (background: paint(something)) {
@property --gradPoint {
syntax: '<percentage>';
inherits: false;
initial-value: 40%;
}
}
And then when it comes time to animate it, you can update the value from the initial 40%
to 100%
:
@supports (background: paint(something)) {
.post:hover,
.post:focus {
--gradPoint: 100%;
}
}
This will now enable that smooth gradient transition.
Conclusion #
The @property
rule makes an exciting technology even more accessible by allowing you to write semantically meaningful CSS within CSS itself. To learn more about CSS Houdini and the Properties and Values API, check out these resources:
- Is Houdini Ready Yet?
- MDN Houdini Reference
- Smarter custom properties with Houdini's new API
- Houdini CSSWG Issue Queue
Photo by Cristian Escobar on Unsplash.