Skip to content

[css-conditional-5] Add ability to test for at-rule preludes #6966

Open
@tabatkins

Description

@tabatkins

In #2463 we just resolved to add at-rule(@foo) and at-rule(@foo; desc: value) functions to @supports, to test for whether an at-rule is supported at all, and whether it supports a given desc: value declaration.

It was brought up in the call (and deferred for time) that we should be able to test for support of things in an at-rule's prelude as well, as that can sometimes be significant and potentially change over time. (Especially for at-rules that end in a semicolon instead of a block, as they're nothing but prelude.)

An important point brought up by @emilio (and supported with historical design context by @dbaron) is that part of the "no special-casing needed, It Just Works" feature of @supports is that we can use it to tell if something is dropped as a whole easily, but can't easily test whether some part of a construct is dropped (since that information is not currently signaled by the CSS parsers, and even if parsers are instrumented to flag a parse error, it's possible to miss spots and thus have @supports give an incorrect result).

In the case of preludes, this isn't a problem - they're either supported or invalidate the at-rule as a whole. Thus, adding detection support for them is possible. The question is just how precisely to invoke this.

To avoid any special-casing at all, I suggest we do support passing an entire at-rule in the function, but we just test whether the at-rule as a whole is dropped or not. That is, at-rule(@foo bar baz {...}) (or at-rule(@foo bar baz) for semicolon-ended rules) is allowed, and just detects whether the rule, when parsed, is dropped or not. We do the parsing as if it was the first content in a stylesheet, so at-rule(@import "foo") would return true.

We thus would have three parsing forms for the at-rule function:

  1. Just the at-rule name, at-rule(@foo), which returns whether this is a recognized at-rule name at all. (This doesn't invoke any parsing, but afaik all existing impls do keep up lists of all their recognized at-rules, so this should still be a no-special-case easy check without the possibility of drifting out of sync.)
  2. An entire at-rule, at-rule(@foo bar {baz: qux}), which returns whether or not the at-rule as a whole, when parsed as the first and only content in a fresh stylesheet, is valid or dropped. If the at-rule is valid but drops some of its contents as invalid, such as an unknown descriptor, this will still return true.
  3. An at-rule name accompanied by a descriptor declaration, at-rule(@foo; desc: value), which returns whether the at-rule is recognized, and the given descriptor successfully parses as part of that at-rule. This should be testable by invoking existing parsing functions in a relatively generic fashion.

Some implications:

  • The second form implies that any required descriptors have to be passed as well; at-rule(@counter-style foo {}) will fail, because @counter-style requires the 'system' descriptors and either 'symbols' or 'additive-symbols', or else the whole rule is dropped.
  • Also, naively the first and second forms collide grammar-wise; we tell them apart by always invoking the first form when the only non-WS contents of the function are a single at-keyword token.
  • Should a trailing semicolon be allowed for the second form, when it's a semicolon-ended rule? It's not actually grammatically ambiguous with the third form (as the third requires a desc:value after it), but allowing it as a valid second-form invocation is a small wrinkle in parsers. I'm fine either way.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions