
The other day on X, Adam Wathan wondered how to feature detect (Custom Property) Style Queries. While in theory you could use @supports at-rule() for this, in practice you can’t because it has no browser support (… yet).
Drawing inspiration from my previous post on how to detect support for @starting-style, I came up with a similar method to detect support for Style Queries: try actively using them and respond to that.
~
# The Code
If you are here for just the code, here it is:
html {
--sentinel: 1;
}
@container style(--sentinel: 1) {
body {
--supported: ; /* Space Toggle */
}
}
With this you get a Space Toggle for you to use in your code.
Or, alternatively, just put all your styles for when style-queries are supported directly into the @container style() rule
html {
--sentinel: 1;
}
@container style(--sentinel: 1) {
/* Styles go here */
}
Before you tl;dr this post, you might still want to read The problem with Safari 18 section …
~
# How it works
The code works by actively trying to use a Style Query. It sets a --sentinel property on the root element and then lets the body element respond to it – using a Style Query.
html {
--sentinel: 1;
}
@container style(--sentinel: 1) {
/* Style Queries supported! */
}
You can put the styles for when there is support directly in there, but unfortunately there is not an easy way to do the “no support” case.
To work around that, you can try to set up a space toggle inside the of style query.
html {
--sentinel: 1;
}
@container style(--sentinel: 1) {
body {
--supported: ; /* Space Toggle */
}
}
When Style Queries are supported, the result will be a --supported custom property that is set to an empty value. In browsers with no Style Queries support, the --supported property will be the guaranteed-invalid value (of initial). Yes, a Space Toggle.
🤔 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` */
With that --supported Space Toggle in place, you can then use it in your CSS:
body {
--bg-if-support: var(--supported) green;
--bg-if-no-support: var(--supported, red);
background: var(--bg-if-support, var(--bg-if-no-support));
}
~
# Demo
The demo below uses the code shown earlier:
See the Pen
Feature Detect Style Queries (1/2) by Bramus (@bramus)
on CodePen.
If you’re using Safari 18, you might notice it doesn’t work as expected …
~
# The problem with Safari 18
While Safari 18 does come with support for (Custom Property) Style Queries, you might have noticed the previous demo does not work in it.
The culprit: A bug in which the root element cannot be a container in Safari 18 – https://bugs.webkit.org/show_bug.cgi?id=271040.
To work around this bug, you need to move everything down one level in your DOM tree. Like so:
body {
--sentinel: 1;
}
@container style(--sentinel: 1) {
body > * {
--supported: ; /* Space Toggle */
}
}
This means you can’t use --supported to conditionally style the body element itself, which might be OK for your use-case.
☝️ The bug has been fixed in Safari Technology Preview 204 and is included in Safari 18.1.
~
# Safari 18-friendly demo
Here’s a demo of the code that also works in Safari. Note that it can’t be used to style the body element itself.
See the Pen
Feature Detect Style Queries (2/2) by Bramus (@bramus)
on CodePen.
~
# 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.
📝 Feature detect Style Queries Support in CSS.
Awaiting browser support for `at-rule()`, here’s how you do it.https://t.co/uXikYbBM2S pic.twitter.com/iuyVwlAgyX
— Bram.us (by @bramus) (@bramusblog) October 6, 2024
~
🔥 Like what you see? Want to stay in the loop? Here's how:
I can also be found on 𝕏 Twitter and 🐘 Mastodon but only post there sporadically.
Leave a comment