Pewarta Proxy

📋 Server Request & Proxy Logs

Loading active proxy settings...
Developed by Khairul Adha (adhexa.id)
Mengambil log server...

⚙️ Pengaturan Proxy Target

Skip to content

[css-conditional] @supports-condition, for larger feature queries and named reuse #12622

Open

Description

@LeaVerou

Originally, @supports only took a nice (property: value) query that looked exactly like the declaration being queried. Over time, we started expanding it to a parallel CSS meta-syntax, with selector() and now at-rule() referring to at-rules separate from their actual syntax, creating issues such as #6966 or #11118.

This got me thinking: it would be nice if authors could basically stuff the thing they want to detect somewhere without having to know or care what type of CSS syntax it is and how to query support in @supports.

What if we had an at-rule that could be used to store and reference conditions, and can accept any parse-able CSS syntax? It can then be used naked in @supports and resolves to true if the rules nested within the @supports-condition rule do not produce any parse errors.
Direct manipulation over indirection.

CSS grammar is already defined to have robust-enough parsing that it can handle parsing unknown structures, so this should be doable syntactically.

Proposal: Named feature queries

It would be defined as a nested at-rule, that can accept declarations or rules, so it would work like this:

Raw declaration:

@supports-condition --masonry-h {
	display: grid-stack;
	item-direction: row;
} 

/* Equivalent to (display: grid-stack) and (item-direction: row) */
@supports --masonry-h {
	/* stuff */
}

More natural syntax for selector():

@supports-condition --part-v2 {
	&::part(foo):hover,
	&::part(bar)::before:hover {
	}
}

/* Like @supports selector(&::part(foo):hover,	&::part(bar)::before:hover) */
@supports --part-v2 {
	/* stuff */
}

More natural syntax for at-rule() (addressing #11118)

@supports-condition --page-margin {
	@page {
		margin: 0;
		@top-right {
		    margin: 0;
		  }
	}
}

@supports --page-margin {
	/* ... */
}

This also means that we can instantly test the entirety of CSS, with dedicated @supports functions needed only for things that do parse correctly.

And this feeds two birds with one scone: it solves the problem of "how do we use @supports to query XYZ?" and also provides a reuse mechanism.

It almost seems too good to be true, so I wonder if it's feasible implementation-wise to get parse error info for a larger structure like this as a whole. Initial discussion with @tabatkins was promising though!

Named inline feature queries

This can do anything that selector() can, but selector() can still be useful as a shorthand (and we need to keep it for compat).
I think if this direction goes forwards, it could eliminate at-rule() since it hasn't shipped yet and involves a lot of unsolved issues and syntactic awkwardness. Or we could greatly simplify it and offer it only as a shortcut for making simple cases easy (e.g. drop the descriptor argument).

Dedicated functions are still necessary for things that do parse correctly. For example we can't replace font-tech() with

@supports --font-tech-color-COLRv1 {
	@font-face {
		font-family: foo;
		src: url(foo.ttf) tech(color-COLRv1);
	}
}

because this would parse anyway.

To allow reuse for such conditions as well the rule could have a no-contents version:

@supports-condition --font-tech-foo font-tech(foo);

@supports --font-tech-foo {
	/* ... */
}

TBD: Combining named feature queries with inline feature queries

For this to also function as a reuse mechanism, we need a way to build more complex conditions from existing conditions. Bare identifiers cannot be combined with other conditions per the <condition> grammar, so we'd need to wrap it in parentheses for that.

This could either take the form of a bare parentheses syntax (@supports (--my-condition) and (foo: bar)) but that means we can never use (foo) to mean "does this property exist?", which is inconsistent with how style() conditions work.
Or, we could have a function, e.g. condition(--my-condition).

There is also the question of whether the parenthesized syntax is always required or only when combining with other conditions. I'm of the opinion that it should only be required when needed (incremental value for incremental user effort) but Tab feels this opens it up to potential errors. I would counter that in other expression syntaxes, we typically only parenthesize to combine with other terms, no defensively. But I can live with either.

Activity

  1. changed the title [-][css-conditional] `@supports-condition`, for larger syntax and reuse[/-] [+][css-conditional] `@supports-condition`, for larger syntax queries and query reuse[/+] on Aug 19, 2025
  2. changed the title [-][css-conditional] `@supports-condition`, for larger syntax queries and query reuse[/-] [+][css-conditional] `@supports-condition`, for larger feature queries and named reuse[/+] on Aug 19, 2025
  3. moved this from Wednesday Morning to Not this meeting? in CSSWG August 2025 meeting agendaon Aug 19, 2025
  4. moved this from Not this meeting? to Wednesday Morning in CSSWG August 2025 meeting agendaon Aug 19, 2025
  5. tabatkins commented on Aug 19, 2025

    @tabatkins
    Member

    but that means we can never use (foo) to mean "does this property exist?", which is inconsistent with how style() conditions work.

    We super intentionally didn't allow that syntax in @supports from the beginning, so I'm fine with continuing to deny that as a possibility.

  6. SebastianZ commented on Aug 19, 2025

    @SebastianZ
    Contributor

    I really love this proposal! This approach catches all the cases at-rule() falls short of like testing for preludes and support for whole at-rules.

    We just need to make sure that the spec. clearly states that anything inside of an @supports-condition is really just parsed to avoid any side effects. And we should make sure to allow at-rules to be tested that are currently only allowed at the top level.

    Sebastian

  7. Crissov commented on Aug 19, 2025

    @Crissov
    Contributor

    I think I like it, too, but for the “More natural syntax for selector()”, I’m afraid an empty rule block might be optimized away together with its selectors, so I’d suggest to put something inside.

  8. AtkinsSJ commented on Aug 19, 2025

    @AtkinsSJ
    Contributor

    This seems like a very neat solution to multiple problems! My initial concern was how to disambiguate the parsing between declarations and style rules, but I think that's already solved because otherwise nesting wouldn't work. Though... if you wanted to test both a declaration and something else in the same @supports-condition, it gets a bit weird that declarations can be raw like that. eg, what context are we parsing things in here?

    @supports-condition --multiple-things {
    	color: light-dark(red, green);
    	@page {
    		margin: auto;
    	}
    }

    Declarations could always be tested with * { /* declarations here */ } so maybe the raw-declarations thing isn't necessary? It's nicer to author but just makes things a bit more confusing.

    I think I like it, too, but for the “More natural syntax for selector()”, I’m afraid an empty rule block might be optimized away together with its selectors, so I’d suggest to put something inside.

    I don't think that's an issue. An empty style rule can't be optimized away because it's observable through the CSSOM. (Also, inside a supports query you're just testing if something can parse, not that it would exist and be useful, so there shouldn't be any such optimizations done.)

  9. 33 remaining items

  10. cdoublev commented on Nov 4, 2025

    @cdoublev
    Collaborator

    We should do the same thing we resolved on for custom media queries

    What you resolved on does not seem very explicit. 😟

    Given the CSS below, what should be the computed color of div when the media width is greater than 500px at parse time? and if it becomes lower than 500px?

    (edit) According to the discussions in #12627, it would be red, and would remain red regardless of how the media condition evaluates.

    div {
      @supports-condition --name {/*everything is supported*/}
      @media (width > 500px) {
        @supports-condition --name { unknown: value; }
      }
      color: red;
      @supports (--name) {
        color: green;
      }
      @supports-condition --name {} /* always ignored? */
    }

    (edit) wrapped --name in () block as required by the syntax, see next comment.

    In any case, I expect that @supports-condition with the same name will not be dropped, like other at-rules registering named things.


    It would be great to clarify this:

    Anything inside the block is evaluated to test whether the user agent supports the features used.

    Should these values evaluate to true?

    • style { /* comment */ }
    • style { oups; }
    • style { @media --oups {} }
    • style { @media (oups) {} }
    • style { color: green; color: green; }
  11. bramus commented on Nov 4, 2025

    @bramus
    Contributor

    We should do the same thing we resolved on for custom media queries

    What you resolved on does not seem very explicit. 😟

    Isn’t that detailed in #12536 (comment)?

    … we've resolved that all this "stylesheet-level" stuff (custom media, Mixins, etc) are defined "as you parse", so you use whatever definition is available at the moment (and that might change if you see another rule defining the same name later).


    Sidenote: Having been AFK for a week and now seeing @supports --name { … } it took me a while to decipher. I first read it as “Is the dashed ident --name” supported, whereas it’s “Is the custom condition --name supported”? Maybe we need something extra around --name in @supports --name { … }? Cfr. what @dbaron said before.

  12. cdoublev commented on Nov 4, 2025

    @cdoublev
    Collaborator

    Thanks, I had not scrolled down. ^^

    But this does not tell whether a nested condition is "available" when its parent condition evaluates to true.

    (edit) According to the discussions in #12627, the parent condition is ignored so the nested named support condition is "available".

    Maybe we need something extra around --name in @supports --name { … }?

    The syntax currently requires a () block.

    <supports-decl> = ( [ <declaration> | <supports-condition-name> ] )

  13. SebastianZ commented on Nov 5, 2025

    @SebastianZ
    Contributor

    @bramus @cdoublev:

    We should do the same thing we resolved on for custom media queries

    What you resolved on does not seem very explicit. 😟

    Isn’t that detailed in #12536 (comment)?

    To me and obviously also @sorvell, that explanation was still somewhat vague. Therefore, I've expressed my interpretation in the other issue.

    @emilio:

    If multiple @supports-condition rules are defined with the same name, the last one in document order wins, and all preceding ones are ignored.

    That's not great. We should do the same thing we resolved on for custom media queries, see #12536 (comment). Otherwise it requires multiple passes to update the active style.

    I agree that we should do the same thing as for custom media queries.

    @cdoublev:

    It would be great to clarify this:

    Anything inside the block is evaluated to test whether the user agent supports the features used.

    True, some more detailed explanation and examples may help here. My expectation is:

    Should these values evaluate to true?

    • style { /* comment */ }

    It's valid even when there are no properties defined, so yes. And there is already an example related to nesting in the spec.

    • style { oups; }

    oups; is not a valid declaration, so no. The spec should be clarified to say that everything nested inside @supports-condition and must be recognized by the UA.

    • style { @media --oups {} }

    As it stands here, --oups would be interpreted as a media type, which doesn't exist, so no.
    If it were wrapped in parentheses, it'd be intrepted as custom media query. In that case, I'd argue we should apply the rules resolved on in #12536. So I'd say, only if the custom media query is defined at that point, it should evaluate to true.

    • style { @media (oups) {} }

    oups is not a recognized media feature, so no.

    • style { color: green; color: green; }

    No issue with repetition, so yes.

    Sebastian

  14. cdoublev commented on Nov 5, 2025

    @cdoublev
    Collaborator

    Based on your answers, it must evaluate to false whenever consume a block's contents get nothing from consuming a rule or a declaration, and forgiving parsing must be disabled.

    I have not included examples with @charset, @import, @namespace.

    A different but related problem is that @supports-condition may be restricted to nested style/grouped rules when nested in a style rule, according to CSS Nesting.

    style {
      @supports-condition --name { @font-face {} }
      @supports (--name) {} /* evaluates to false even if @font-face is supported */
    }

    But these are minor problems that can be fixed later and discussed in a separate issue, I guess.

  15. SebastianZ commented on Nov 6, 2025

    @SebastianZ
    Contributor

    All good points! While I initially specced @supports-condition, it was @LeaVerou's suggestion and she got added as editor to the spec. So I refer to her to further adjust the definition.🙃

    Sebastian

  16. cdoublev commented on Nov 6, 2025

    @cdoublev
    Collaborator

    A different but related problem is that @supports-condition may be restricted to nested style/grouped rules when nested in a style rule [...]

    After rereading previous discussions more carefully, it might not be a problem but rather intentional: @supports-condition block value should accept any valid content in the context, if I am not mistaken. (The spec currently includes an example with top-level property declarations.)

    Other questions/concerns:

    • should the block contents of a top-level @supports-condition be parsed like a style sheet or a block contents? (they have different content end tokens)
    • should authors be allowed to update @supports-condition contents via CSSSupportsFunctionRule?
    • why CSSSupportsFunctionRule does not extend CSSConditionRule while @supports-condition is defined as a conditional group rule?
    • how to compute CSS.supports(--name)?
  17. added a commit that references this issue on Feb 4, 2026
  18. css-meeting-bot commented on Mar 25, 2026

    @css-meeting-bot
    Member

    The CSS Working Group just discussed [css-conditional] `@supports-condition`, for larger feature queries and named reuse, and agreed to the following:

    • RESOLVED: Use @supports (--foo) for custom supports conditions.
    The full IRC log of that discussion <fantasai> lea: Specific grammar questions from @cdoublev
    <TabAtkins> here we go https://github.com//issues/12622#issuecomment-3435923624
    <fantasai> lea: Sebastian added to the discussion here...
    <fantasai> lea: Ideally Sebastian presents this?
    <fantasai> TabAtkins: I think I can present this one now.
    <fantasai> TabAtkins: Like Lea said, question is how do you refer to a custom supports condition in an @supports rule?
    <fantasai> TabAtkins: 2 possibilities
    <TabAtkins> whether it's (--foo)
    <fantasai> TabAtkins: 1. Parenthesize it, but use dashed-ident.
    <TabAtkins> condition(--foo)
    <fantasai> TabAtkins: 2. Define a new query function, which takes the name of the condition.
    <lea> q+
    <Rossen> style {
    <Rossen> @supports-condition --name { @font-face {} }
    <Rossen> @supports (--name) {} /* evaluates to false even if @font-face is supported */
    <Rossen> }
    <fantasai> TabAtkins: I think that example is asking questions about nesting.
    <fantasai> TabAtkins: Question is about how to refer to it in the supports rule.
    <fantasai> TabAtkins: Concern with taking the name directly in parens is that it will prevent us from using that exact syntax for testing whether a property name is supported at all
    <fantasai> TabAtkins: Other syntax we have is (property: values)
    <fantasai> TabAtkins: We intentionally didn't add (property) to @supports so that we engage the CSS parser and get a true result
    <fantasai> TabAtkins: Not a separately (and likely brokenly) maintained list in the browser
    <fantasai> TabAtkins: So I think using bare name is fine here.
    <fantasai> TabAtkins: Function is also fine with me, but more typing
    <Rossen> ack lea
    <fantasai> lea: Not a strong position either. Concerned about function vs custom media queries, which use bare idents
    <fantasai> lea: Also question about nesting and how do multiple rules combine or what
    <fantasai> lea: I cannot see a use case with wanting to interleave with regular elements, usually you define up front and then use
    <fantasai> lea: I don't see what you might want to detect around bare idents
    <fantasai> lea: Already a way to detect custom properties, though I can see why it feels too similar
    <Rossen> ack fantasai
    <TabAtkins> @media (--foo)
    <fantasai> fantasai: Beign consistent with MQ makes sense to me.
    <fantasai> s/Beign/Being/
    <fantasai> dbaron: Fine with this, but if we take this syntax in @supports rules then we'll also take this anywhere a declaration can be used
    <fantasai> dbaron: So as long as we're ok saying "we're not going to allow single custom keyword in places where you write property-value pairs" then this is fine. But that's a slightly bigger reservation of syntax than what some people are talkinga bout.
    <Rossen> ack dbaron
    <fantasai> TabAtkins: you mean inside a style rule?
    <fantasai> dbaron: Yeah
    <fantasai> TabAtkins: We are using at-rules for that, so I think it's OK.
    <TabAtkins> fantasai: because we ahve custom idents for custom properties... and just dropping the value of the custom prop woudl be subtle for a new feature, it's probably okay to resolve that we won't do that
    <TabAtkins> fantasai: and the consistency with MQs is a pretty strong argument for doing this, if we don't have strong reservations agaisnt it
    <fantasai> PROPOSED: Use @supports (--foo) for custom supports conditions.
    <fantasai> RESOLVED: Use @supports (--foo) for custom supports conditions.
    <Rossen> ack fantasai
    <fantasai> fantasai: Lea brought up questions about how to handle multiple rules with the same name, etc. Are we tackling those questions here also?
    <fantasai> TabAtkins: Relying on last wins.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions