This content originally appeared on Bram.us and was authored by Bramus!
Today on Mastodon, Nils asked how to detect support for @property
. While in theory you could use @supports at-rule()
for this, in practice you can’t because it has no browser support ().
Thankfully, there’s a workaround … by trying to actively use registered custom properties and style things based on the outcome.
~
Feature detecting @property
support with Style Queries
This trick involves registering a Custom Property --supported-sentinel
property with a specific initial-value
. When then trying to use it inside var()
the resulting value will either be that initial value or the fallback you provide. In the following snippet below the value for --supported
will be either 1
in browsers with support or 0
in browsers with no support for @property
@property --support-sentinel {
syntax: "<number>";
initial-value: 1;
inherits: false;
}
:root {
--supported: var(--support-sentinel, 0);
}
Using Style Queries you can then style children of :root
based on the value of --supported
:
/* No support */
body {
background: red;
}
/* Has support */
@container style(--supported: 1) {
body {
background: green;
}
}
The downside of this method is that the browser also needs to support Style Queries, which currently are only supported in Blink/Chromium. I’m sure Jane can remix this to use Type Grinding
Demo
~
Feature detecting @property
support with a Space Toggle
A detection with broader support is to use a Space Toggle. One downside is that it requires JavaScript to register the toggler because of differences between browsers.
What’s a Space Toggle?
If you are unfamiliar with the Space Toggle Hack, it’s a hack that relies on a custom property that you toggle between two values: it’s either a space (
) or initial
. The former indicates that it’s ON and the latter that it’s OFF.
--toggler: ; /* = ON */
--toggler: initial; /* = OFF */
You use this property to generate other values: a value for when it’s ON and a value for when it’s OFF.
It relies on CSS eating spaces (e.g. green
becomes simply green
) and CSS falling back to the fallback value when var()
refers to a custom property that contains initial
.
Behavior when it’s ON (
):
--toggler: ; /* = ON */
--value-when-on: var(--toggler) green; /* = ` green` = `green` */
--value-when-off: var(--toggler, red); /* = ` ` or `red` = `red` */
background: var(--value-when-on, var(--value-when-off)); /* = `green` or ` ` = `green` */
Behavior when it’s OFF (initial
):
--toggler: initial; /* = OFF */
--value-when-on: var(--toggler) green; /* = `initial green` = `initial` */
--value-when-off: var(--toggler, red); /* = `initial` or `red` = `red` */
background: var(--value-when-on, var(--value-when-off)); /* = `initial` or `red` = `red` */
This trick also involves registering a custom property but you give it an initial-value
of a single space.
CSS.registerProperty({
name: '--supported',
syntax: '*',
initialValue: String.fromCharCode(0x20), // (or just use ' ')
inherits: false
});
In browsers with support, the value for --supported
will be that space. In browsers with no support, the value for --supported
will be the guaranteed initial value of initial
. Yes, a classic Space Toggle indeed!
body {
--bg-if-support: var(--supported) green;
--bg-if-no-support: var(--supported, red);
background: var(--bg-if-support, var(--bg-if-no-support));
}
Why can’t you rely on registering the Custom Property using CSS?
Up until 2023 it wasn’t possible to register a Custom Property without an initial-value
. Because the CSS parser eats up spaces it wouldn’t recognize a space as the initial-value
, so the following code wouldn’t work.
@property --supported {
syntax: '*';
initial-value: ;
inherits: false;
}
With the spaces being eaten, the parser would think the initial-value
was missing, and thus it would discard the entire registration. This got fixed at the spec level after I filed a CSSWG Issue for this: the initial-value
descriptor is now optional when the syntax is set to *
.
While the behavior got updated in Chrome 119 thanks to this commit, you shouldn’t rely on the CSS registration because that would exclude Chrome versions 85-118. Furthermore Safari doesn’t seem to like this CSS registration variant whereas Firefox (with feature flag at the time of writing) OTOH does play nice with it.
Demo
~
Spread the word
Feel free to repost one of the posts from social media to give them more reach, or link to this post from your own blog.
New post: How to feature detect support for @property in CSShttps://t.co/SuXh83X719#css #featuredetection #atproperty
— Bram.us (by @bramus) (@bramusblog) July 3, 2024
~
Like what you see? Want to stay in the loop? Here’s how:
This content originally appeared on Bram.us and was authored by Bramus!