Repository navigation
[css-conditional-5] Add ability to test for at-rule preludes #6966
Description
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:
- 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.) - 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. - 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:valueafter it), but allowing it as a valid second-form invocation is a small wrinkle in parsers. I'm fine either way.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsWednesday Morning
Activity
yisibl commentedon Aug 25, 2022
We have so many at rules today. It does need a good mechanism to detect if they are supported or not.
mirisuzanne commentedon Aug 30, 2022
This is relevant for browsers that want to ship style container queries, along with a feature query for testing support. I left more details in #6175 (comment), but I think thread this is actually the proper place to make progress on the issue.
Would it be ready to bring back as a proposal with agenda+, or is there more discussion that needs to happen here? @tabatkins summary above looks reasonable to me, and better than one-offs like the
@supports container()syntax that we approved in the other thread./cc @lilles
mirisuzanne commentedon Aug 31, 2022
Agenda+ to see if we can get this resolved, and/or get concrete feedback on the proposal.
css-meeting-bot commentedon Sep 16, 2022
The CSS Working Group just discussed
At-rule Prelude Tests.The full IRC log of that discussion
<fantasai> Topic: At-rule Prelude Tests<fantasai> github: https://github.com//issues/6966
<fantasai> TabAtkins: earlier we defined testing for at-rules and descriptors, which we can do generically by throwing it at a parser
<fantasai> TabAtkins: we don't have ability to check if prelude of atr-ule is valid or not
<fantasai> TabAtkins: this should follow the same "throw at parser and see", but not possible atm
<fantasai> TabAtkins: especially important for at-rules that don't have blocks, e.g. @layer statement form
<fantasai> TabAtkins: you can test @layer at all, but not specifically for @rule statements
<fantasai> TabAtkins: suggest we take the first form of the at-rule syntax and allow it to take more
<fantasai> TabAtkins: parse all of that as the prelude
<miriam> q+
<fantasai> TabAtkins: as long as it passes your parser check, it's OK
<heycam> q+
<fantasai> miriam: I think this is also required for testing whether style queries are supported
<astearns> ack heycam
<fantasai> heycam: I'm wondering if there's any benefit from having this called "rule" rather than "at-rule", can we match any kind of rule not just at-rules?
<fantasai> TabAtkins: unless you know the context you're parsing in, there's only one type of rule and it's style rule
<fantasai> heycam: for those rules you can rely on selectors and individual properties
<heycam> fantasai: to summarize, three parsing forms for at-rule function
<heycam> ... one just takes the name
<heycam> ... one takes the entirety of the rule, and if anything is dropped, then it returns false
<fantasai> https://github.com//issues/6966
<heycam> ... and the third is the existing descriptor, `@foo; descriptor:value`
<TabAtkins> at-rule(@foo bar {baz: qux}),
<fantasai> fantasai: That would let you do complicated nesting structures as well
<fantasai> TabAtkins: If feed into parser, is the top-level rule kept or not. Ignoring inside things.
<heycam> fantasai: I think that would not be hepful
<fantasai> TabAtkins: more specific, would require more specific plumbing in browsers
<fantasai> TabAtkins: to report pass or failure
<fantasai> TabAtkins: and also it's more powerful than you necessarily wanted
<heycam> fantasai: I think if we want to add a full whole thing kind of syntax, then we should be parsing everything in there and if anything is dropped, you fail
<heycam> ... if you want it more limited
<heycam> ... if you want to check statement vs block, then add curly quotes
<heycam> ... as soon as you put something in there, authors will expect it's testing everything in there
<heycam> ... if we allow dropped things, authors will be confused, and we won't have an extension mechanism in the future
<heycam> fantasai: authors are going to expect that when you put a test in @supports it's everything you put in there that you're checking
<florian> q+
<heycam> fantasai: fine to add more specific syntaxes, but authors are going to expect if you add in @supports, it's checking the full thing is understood
<heycam> miriam: I agree
<heycam> emilio: yes
<fantasai> TabAtkins: That is something that was specifically called out, that bubling up invalidity is problematic
<chris> s/emilio/chris/
<heycam> TabAtkins: that was specifically called out as problematic in an earlier discussion
<heycam> fantasai: so limit the syntax
<heycam> fantasai: that's fine, if you want to do nested structures, do it properly
<astearns> ack florian
<fantasai> ^TabAtkins: then do nested structures
<fantasai> florian: We don't want @supports to be smart. Want to use the actual parser
<fantasai> florian: if we start to maintain some degree of logic, then that logic can get out of sync with reality
<fantasai> s/do nested/don't do nested/
<fantasai> s/don't/can't/
<fantasai> florian: usefulness of at-supports will decrease if we try to be smart about it, because will be less reliable
<heycam> fantasai: I think it's more important that anyything we allow in @supports ,the author can rely it's testing the whole thing
<heycam> ... I think that's more important than the concern that it might get out of sync
<heycam> TabAtkins: I disagree. author confusion is substantially better than UA lying.
<heycam> fantasai: the UA is effectively lying from the perspective of the author
<emilio> q+
<fantasai> fantasai: if you let it ignore stuff that is inside @supports check
<fantasai> astearns: This is an issue about preludes, so how about we just add preludes and not address nesting
<fantasai> TabAtkins: so we would just take the prelude, not semicolon
<astearns> ack emilio
<fantasai> emilio: I agree with TabAtkins, it's weird to suddenly pass e.g. @font-face rule, and you read the descriptors and the ones you care about you keep and the others you ignore
<TabAtkins> Authors being confused means the author can fix this, by doing it right. UAs lying means the author can't fix this; they're just screwed. UA lying is *meaningfully different* from author confusion.
<fantasai> emilio: it would require this special mode, then you have to find the places
<heycam> fantasai: I'm not arguing with you on this point
<heycam> ... if you're going to allow the syntax in @supports, then you must check all of it
<heycam> ... if you don't want that, don't allow it in the syntax
<fantasai> astearns: So proposed resolution is allow @rule preludes in the syntax, and check them for validity
<fantasai> fremy: You have at-rule in the prelude, what if at-rule is only valid inside another at-rule?
<fantasai> TabAtkins: This should still be fine, you won't be able to do any parent-child checking
<fantasai> TabAtkins: but this sub-atrule gets parsed somehow
<fantasai> TabAtkins: only problem is if you have two different at-rules that have different children with different names
<TabAtkins> s/different name/same names/
<astearns> ack fantasai
<heycam> fantasai: if I say @at-rule(@media foo), will that parse as supporting querying against foo?
<heycam> ... that's not going to cause the media rule to be invalidate, I'm asking whether you support that media rule
<florian> q+
<heycam> ... if it's going to return true for anything that appears after @media, that's not useful
<heycam> TabAtkins: [missed]
<fantasai> s/useful/useful, and it is confusing and unexpected to the author/
<fantasai> emilio: We have custom parsing for unforgiving selectors, right?
<fantasai> TabAtkins: Still, I suspect that this is a distinctly different thing because switching between selector lists isn't straightforward
<fantasai> emilio: but there is some amount of precedent, not that I love it
<fantasai> florian: for fantasai's example about media queries, it's undecideable
<fantasai> florian: because, telling the difference between whether you support querying whether running on 3D printer vs asking, you can't distinguish as an author
<heycam> fantasai: let's take a better example
<fantasai> florian: you'll get a "no", which is the correct answer
<fantasai> fantasai: consider the touchscreen MQ
<heycam> ... if the author asks do you support querying whether this is a touchscreen, and you say sure, I support every media query ever
<heycam> ... then the author will assume you support the media query
<heycam> TabAtkins: they'll get a no when they actually use the MQ
<heycam> fantasai: maybe they want to figure out some other heuristics?
<heycam> ... maybe I'll change my layout if you don't support this MQ, and cannot know from the MQ whether you support a touchscreen
<heycam> ... but you don't have the ability to check that
<heycam> ... not saying you necessarily don't need this feature, I am saying if you put it in an @supports query, the author will reasonably expect the browser will check if it understands that MQ, and we should not violate that expectation
<fantasai> TabAtkins: Anything that requires custom parsing
<fantasai> fantasai: then don't allow it
<fantasai> TabAtkins: either you can never test for preludes, or for some extremely forgiving syntaxes, this query is not going to be maximally useful
<fantasai> TabAtkins: and we can introduce a new query later
<fantasai> TabAtkins: either we don't allow preludes at all, or we accept that @media is confusing
<TabAtkins> TabAtkins: And we fix it in the future with a `media-feature()` query
<fantasai> astearns: Is that going to be acceptable, to allow testing for preludes with this possibly workaroundable thing?
<fantasai> fantasai: depends what other people think? I'm only one member of this WG
<fantasai> miriam: I agree with both of you.
<fantasai> miriam: so that's helpful!
<fantasai> florian: I'm lost about the overall discussion, but I think @supports testing of media queries is not useful given current form of media query
<heycam> fantasai: how forgiving is parsing on CQs?
<fantasai> miriam: So the problem is specific to media queries, we don't have the problem with container queries right?
<fantasai> emilio: it's same
<fantasai> emilio: also have same problem with @supports itself
<fantasai> florian: well people won't use @supports @supports
<fantasai> florian: nobody will do that one so it doesn't matter
<TabAtkins> Anything with `<general-enclosed>` in the grammar is forgiving in this way, and won't be good to test.
<fantasai> miriam: People do wwant to know whether @supports of selectors works
<fantasai> TabAtkins, yeah, but authors can't figure that out
<fantasai> TabAtkins, it's totally opaque to them
<TabAtkins> yeah, i'm just answering the question
<fantasai> miriam: SO what's the solution that gets us there?
<fantasai> florian: MQ was designed to work around the problem. When browser doesn't know how to answer it doesn't know how
<fantasai> florian: [...]
<fantasai> fremy: You can design the query so you get the support you want
<fantasai> florian: if you want a third design where you don't know whether your design can over, this is tricky
<fantasai> TabAtkins: we can let author ssolve that with custom MQ
<fantasai> TabAtkins: because that's what they do today
<fantasai> miriam: Does @else help? Means you can just attach a negation to the query itself
<florian> s/design can over/design can hover/
<fantasai> TabAtkins: top-level query is alwasy true or false, unknown is not a response
<fantasai> emilio: For @media, can't you do that? Ask for a logical combination of your query and not your query
<fantasai> emilio: e.g. @media hover and not hover, and that should be true on all browsers that support hover and not on ones that don't
<fantasai> emilio: I mean 'or'
<fantasai> emilio: so can do that with CSS already, though not beautiful
<TabAtkins> (true or false) is true, (unknown or unknown) is unknown (and thus false)
<TabAtkins> so yeah that works
<fantasai> florian: for media features yes, but not media types
<fantasai> TabAtkins: I think we have multiple ways to address the media being restrictive
<fantasai> TabAtkins: I would be very sad if, though we have ways to address it, we lost ability to do anything else that doesn't have forgiving this nature
<fantasai> TabAtkins: fantasai, can you let us do this as specified, if other feautres can let you figure out media queries
<heycam> fantasai: I can live with it, but I really do want to hear from others in the room
<fantasai> astearns: Proposed resolution is to allow testing of at-rule preludes in supports, using the prelud syntax and no nesting as yet
<fantasai> florian: I suggest we include a note that things that have forgiving parsing will say yes, and it doesn't mean that they are support
<heycam> fantasai: I think it will confuse a lot of people, but I understand we do want to do this for other things for which it does make sense
<heycam> ... my concern for CQs is that if we have to invent a new function for say state queries, they'll ask if that's supported, and we'll say yes
<fantasai> miriam: This doesn't work for the things I want it to work for
<emeyer> q+
<fantasai> miriam: and I agree it'll confuse people
<florian> q-
<astearns> ack florian
<fantasai> miriam: I wonder if we can restrict it to just the things that it's useful for?
<fantasai> TabAtkins: we could maybe do that, say it doesn't do anything on @media/@supports/@container
<astearns> ack emeyer
<fantasai> emeyer: I think Tab addressed my concern.
<fantasai> emeyer: I'm concerned we're starting to cross into territory.... I agree with Elika's point that this will be confusing in these cases
<fantasai> emeyer: if we restrict from those cases, then it's ok with me
<fantasai> emeyer: @supports is already a bit confusing, e.g. @supports (text-decoration: blink)
<fantasai> emeyer: I was concerned that we would introduce a class of problems that authors would be *much* more confused about
<fantasai> emeyer: but I believe the syntax restrictions would address my concerns
<fantasai> astearns: what would it address?
<heycam> fantasai: anything with forgiving syntax
<fantasai> TabAtkins: we have 27 at-rules ...
<fantasai> florian: Anything with <general-enclosed>
<TabAtkins> s/27/20-something/
<fantasai> florian: Alternative is if you hit <general-enclosed>, return false
<fantasai> TabAtkins: that's specialized parsing
<fantasai> heycam: so it's that the condition, if you use an at-rule(@media ...) it's not invalid, it's just false?
<fantasai> florian: would prefer invalid, so if we figure out how to solve we can make it work
<fantasai> astearns: I've lost state of proposed resolution
<TabAtkins> Proposed resolution: allow testing at-rule preludes. Exclude @media, @supports, and @container from this form fo the test; they're invalid to use.
<TabAtkins> (Generally, anything using <general-enclosed>, but for now it's those three.)
<fantasai> florian: Can you clarify, they're invalid, does that mean they return false or they fail to parse?
<fantasai> TabAtkins: they make the rule invalid
<fantasai> florian: what do you mean by "the rule"
<heycam> fantasai: it's as if you wrote foobar() instead of at-rule()
<heycam> TabAtkins: foobar() is a false query
<fantasai> astearns: We will work out what the remaining proposal is in the future for specific syntax and behavior in a summary ocomment form TabAtkins
<fantasai> TabAtkins: I gave the proposed resolution, ignoring that bit about clarifying invalid
<fantasai> astearns: Let's get it written out, and then come back to it
<fantasai> astearns: because I've had several ppl ask that we get to Toggles!
<florian> "@support at-rule(@media foo) or (display:block) { :root{ color: blue ) }" What does that do, blue or not blue?
mirisuzanne commentedon Sep 19, 2022
@emilio after the meetings, you mentioned it might be possible to do strict parsing of query syntaxes inside
@supports- eg failing on unknown queries? Does that seems like a viable approach that doesn't require too much special casing?lilles commentedon Dec 15, 2022
Could we make
<general-enclosed>and parts of media/container queries that are unknown, including unrecognized media type fail the@supports at-rule()query?We resolved on a similar behavior for forgiving selectors for
@supports selector().mirisuzanne commentedon Jan 4, 2023
Agenda+ to see if we can resolve on @lilles suggestion above. I think it would be a significant improvement, if we can do it.
mirisuzanne commentedon Feb 2, 2023
Sorry, I was over-eager putting this on the agenda. It looks like where we left off after TPAC, we still need to re-form the basic proposal - and then we can include this update to the proposal.
24 remaining items
Bug 1928335 [wpt PR 48907] - Implement at-rule for use with @supports.…
[css-conditional-5] Spec at-rule() per CSSWG resolutions. w3c#2463, w…
Update at-rule() implementation and test to match CSSWG resolutions
Update at-rule() implementation and test to match CSSWG resolutions
Update at-rule() implementation and test to match CSSWG resolutions
Update at-rule() implementation and test to match CSSWG resolutions
[css-conditional-5] Spec at-rule() per CSSWG resolutions. #2463, #6966,
Bug 1994290 [wpt PR 55430] - Update at-rule() implementation and test…
Update at-rule() implementation and test to match CSSWG resolutions
Rescopes at-rule down to test to just `at-rule(@foo)`
Re-scopes at-rule (#1231)