Using CSS can I check if a browser supports the "CSS Properties and Values API" (Houdini) @property rule
Asked Answered
L

3

8

With some browsers starting to introduce the CSS Houdini API, I was wondering if there were any ways to identify if the CSS Properties and Values API is supported with CSS alone?

With Javascript I'm able to check if the API exists: ✅

typeof window.CSS.registerProperty !== 'undefined'

Are there any equivalences native to CSS? I was experimenting with the @support rule, but this only accepts properties and values -- not 'at-rules'. So the following will understandably not work. ❌

@property --my-color {
  syntax: '<color>';
  inherits: false;
  initial-value: #c0ffee;
}

@supports ( @property : --my-color ) {
  body { background:DarkSeaGreen ; }
}

@supports not ( @property : --my-color ) {
  body { background:Crimson; }
}

☝️ CodePen Example

Lippe answered 18/10, 2021 at 8:23 Comment(0)
T
6

Edit 2. 2024: Jane Ori's investigation and POC suggests using rlh units support as a signal of @property support, i.e. adding (width: 1rlh) to the paint() support check to spread it to Firefox and Safari (and check them with their specific properties to be sure); see @supports @property CodePen by Jane Ori CodePen.

Edit 1. 2024: Firefox finally received support for declarative CSS OM, but still lacks the paint worklet support, so assumptions of this answer turned out to be off. Edited accordingly.

Edited original answer

Apparently best we could do at that point was to pretend that support of paint worklet denoted support of declarative CSS Typed OM @property in style sheets: unlike @property, <property-accepting-image>: paint(<ident>) can be used in @supports block.

Una Kravets used this in her @property dev.to article:

@supports (background: paint(something)) {
  /* [Typed OM `@property` should be supported here] */
}

but removed this pattern later in 2024-06, so the current version of the @property dev.to article does not contain this advice.

She also noted that this is (was) not reliable in Chromiums from version 78 up to v84.

For the state of browsers before 2024 according https://ishoudinireadyyet.com/ (this page does not seem to be updated for the 2024 state now in 2024 yet) it should have been safe to use the recommendation:

ishoudinireadyyet.com table showing that all browsers supporting the Paint API also supports CSS Typed OM

It seemed plausible that UAs newly adopting Houdini will release support both for paint API and CSS OM in style sheets simultaneously, i.e. the Chromium v84 scenario will not happen again. (And if it will, my bet is the Typed OM will be released prior to paint worklet, so the condition will be (unnecessarily) ignored in that versions.) Well, I've lost the bet.

Testerman answered 18/10, 2021 at 12:0 Comment(0)
B
3

Firefox's Support = TBC Experimental

I guess paint(...) will be far from Firefox's supports, but Firefox is already doing some experimental supports on CSS Properties and Values via layout.css.property-and-value-api.enabled and layout.css.properties-and-values.enabled.

layout.css.property-and-value-api.enabled

layout.css.properties-and-values.enabled

  • It can be turned to true in about:config to get window.CSS.registerProperty being supported.
  • It does not really mean you can use @property.
  • Using typeof window.CSS.registerProperty !== 'undefined' is not guaranteed to have the support on @property.
  • Note: Starting from Firefox 120, it is truly supported

CSS Detection

No @supports for @property

There is no @supports (@property) {...}.

You can use pure CSS or JavaScript to detect this feature is supported or not. (For pure CSS, it can just display the text to tell you it is not supported.)

Pure CSS Detection via Pseudo Element's content

  • Set a number property --num with initial value above 0. (number 3)
  • Use counter and counter-style to generate the support message with number 3 and unsupported message with number 0.
@property --my-color {
  syntax: '<color>';
  inherits: false;
  initial-value: #c0ffee;
}

@property --num {
  syntax: "<integer>";
  initial-value: 3;
  inherits: false;
}

@counter-style my-style-fallback {
  system: cyclic;
  symbols: 'Not Supported''Not Supported';
}

@counter-style my-style {
  system: cyclic;
  symbols: 'Supported''Supported';
  range: 2 4;
  fallback: my-style-fallback;
}

#result-css {
  counter-set: num var(--num);
}

#result-css::after {
  content: 'Not Supported';
  content: counter(num, my-style);
}

JavaScript Detection

No try catch block with CSS.registerProperty

  • Note: At the time I write this post, it is still not handled correctly in Chrome.

The following code

window.CSS.registerProperty({
  name: "--my-color",
  syntax: "<color>",
  inherits: false,
  initialValue: "#c0ffee",
});

might not raise any error if you have defined the property via CSS not via JavaScript.

Note: If you use registerProperty to register the property name that defined in CSS, then error might come and at the same time the property is being override.

Detection by getComputedStyle

Since every CSS properties are well defined with type and initial value, you can use getComputedStyle API to check it.

window.getComputedStyle(document.documentElement).getPropertyValue('--my-color');

In your case, the result shall be "#c0ffee". If it is not defined, the result will be "".

Combined Coding Demo for Reference

jsFiddle version

const resultByJs = window.getComputedStyle(document.documentElement).getPropertyValue('--my-color');


document.getElementById('result-js').textContent = resultByJs === '' ? 'Not Supported' : 'Supported'
@property --my-color {
  syntax: '<color>';
  inherits: false;
  initial-value: #c0ffee;
}

@property --num {
  syntax: "<integer>";
  initial-value: 3;
  inherits: false;
}

@counter-style my-style-fallback {
  system: cyclic;
  symbols: 'Not Supported''Not Supported';
}

@counter-style my-style {
  system: cyclic;
  symbols: 'Supported''Supported';
  range: 2 4;
  fallback: my-style-fallback;
}

#result-css {
  counter-set: num var(--num);
}

#result-css::after {
  content: 'Not Supported';
  content: counter(num, my-style);
}
<html>


<div>
  <h3>`@property` checking by CSS</h3>
  Result: <span id="result-css"></span>
</div>


<div>
  <h3>`@property` checking by JS</h3>
  Result: <span id="result-js"></span>
</div>


</html>

Remarks added on 2023/12/15

It has been tested that, Firefox 120 (Stable) can enable CSS Houdini using layout.css.properties-and-values.enabled = true

However, it is still not yet supported with Animation API.

Further Remarks: The support starts from Firefox Nightly 123.0a1 (2023-12-30) (64-bit)

Further Remarks: The stable support starts from Firefox 123.0 since 2024.03.02

jsFiddle version

const resultByJs = window.getComputedStyle(document.documentElement).getPropertyValue('--my-color');


document.getElementById('result-js').textContent = resultByJs === '' ? 'Not Supported' : 'Supported'


document.documentElement.animate(
  [
    { '--num': '100' },
    { '--num': '0' }
  ],
  {
    fill: "forwards",
    duration: 1000*30,
    easing: 'linear'
  }
);

let resultByJsA = window.getComputedStyle(document.documentElement).getPropertyValue('--num');

document.getElementById('result-jsa').textContent = `${resultByJsA}`.length > 1 ? 'Supported' : 'Not Supported';
@property --my-color {
  syntax: '<color>';
  inherits: false;
  initial-value: #c0ffee;
}

@property --num {
  syntax: "<integer>";
  initial-value: 3;
  inherits: false;
}


@counter-style my-style-fallback {
  system: cyclic;
  symbols: 'Not Supported''Not Supported';
}

@counter-style my-style {
  system: cyclic;
  symbols: 'Supported''Supported';
  range: 2 4;
  fallback: my-style-fallback;
}

#result-css {
  counter-set: num var(--num);
}

#result-css::after {
  content: 'Not Supported';
  content: counter(num, my-style);
}

h3 {
  display: inline-block; width: 18em;
}
<html>


  <div>
    <h3>`@property` checking by CSS</h3>
    Result: <span id="result-css"></span>
  </div>


  <div>
    <h3>`@property` checking by JS</h3>
    Result: <span id="result-js"></span>
  </div>
  
  
  <div>
    <h3> Animating `@property` checking by JS</h3>
    Result: <span id="result-jsa"></span>
  </div>


</html>
Briony answered 20/8, 2023 at 1:39 Comment(1)
A great rundown and detailed answer. Thank you.Lippe
S
1

You can also use window.CSS.paintWorklet to check houdini api is supported or not.

Shooter answered 20/7, 2022 at 15:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.