Thanks to visit codestin.com
Credit goes to github.com

Skip to content

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

@LeaVerou

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Wednesday Morning

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions