Closed mirisuzanne closed 3 years ago
We've talked about wanting to be able to test for at-rule existence in @supports in the past (I can't find the issues for it right now), but it might very well make sense to just allow a trivial "does this at-keyword look like something you support?" test, like `@supports at-rule(@container) {...}
Both of our solutions exclude the long list of browsers supporting @media
without support for @supports
. In your case, browsers would also have to implement @supports at-rule()
fairly broadly before @container
is available, or it's not terribly useful. In order to use either pattern, authors would be hiding the media-query fallback from a long list of previously-supported browsers. Adding new support syntax might be a good idea long-term (also for layers and scope?), but in the immediate case it seems like it would make the issue more dramatic?
True, but fixing it "better" now makes the next time this problem comes up less troublesome. ^_^
Right, I absolutely support the feature. I'm not sure it solves the immediate issue. :)
That feature would be more powerful if it can also test support for the at-rule condition, like @supports at-rule(@media (prefers-reduced-motion: reduce)) {...}
. As a bonus, I could infinitely nest @supports at-rule(@supports at-rule(@supports at-rule(…))) {…}
, and that would keep me entertained for at least 20 minutes.
Just for reference, with the syntax I suggested in #2463 at-rules with descriptors and with nested rules would be covered for testing via @supports
.
Sebastian
So a few syntax options that I've seen in the comments here or linked…
/* possibly using a function like at-rule() or rule() */
@supports (@container) { … }
@supports (@container (width > 20em)) { … }
@supports (@container, width > 20em) { … }
This would certainly be helpful for things like @container
and new @media
features.
@SebastianZ your linked syntax also includes a style block, since it's mainly concerned with testing descriptors inside a rule. Not clear if that's meant to be required, or part of what you're suggesting here?
@SebastianZ your linked syntax also includes a style block, since it's mainly concerned with testing descriptors inside a rule. Not clear if that's meant to be required, or part of what you're suggesting here?
The syntax is meant to take any kind of at-rule to let the UA do a simple syntax pass to check whether the at-rule is supported or not. So, in the simplest case you'd then have something like this:
@supports (@container { * { color: wheat; } }) {
...
}
There's a lot of power in that, but I think ideally the simplest case could be a bit more focused on the at-rule and its arguments. Maybe if blocks were allowed to be empty?
@supports (@container {}) { ... }
@supports (@media (prefers-reduced-motion: reduce) {}) { ... }
... Maybe if blocks were allowed to be empty?
@supports (@container {}) { ... } @supports (@media (prefers-reduced-motion: reduce) {}) { ... }
Actually, they are, so that is totally valid syntax.
Sebastian
+1 to @mirisuzanne's suggestion of:
@supports (@container {}) { ... }
@supports (@media (prefers-reduced-motion: reduce) {}) { ... }
This is definitely needed and useful for negation to apply styles when progressively enhancing container queries:
@supports not (@container {}) { ... }
This is more resilient than @supports not (contain: inline-size) {...}
because inline containment could be implemented separately of @container
.
The CSS Working Group just discussed [css-contain] What is the migration path for Container Queries?
.
Feels a bit inconsistent not to require at-rule()
or something. You don't need more than one lookahead token to see that this is an at-rule and not a declaration, but still.
@lilles My understanding of the discussion was that we're leaning towards individual functions for each at-rule:
@supports not media(width > 40em) { … }
@supports not container(min-width: 40em) { … }
(Here's a codepen demo of how it might work for Container Queries)
There was also mention of an @else
rule that can be appended to any conditional block:
@container (min-width: 40em) { … }
@else { /* condition is negative */ }
And, while I like that idea, I don't think it does what we want here. I would expect @else
to apply when the condition is negative (width is less than 40em), not when the condition is lacking browser support. I'm not sure we want to conflate those.
Sorry, I wasn't there and posted before I saw the notes. Separate functions sgtm.
So I think some of the concerns @mirisuzanne mentioned (of needing to support this condition way before @container
works) are really an issue, but only because browsers disagree on this case:
CSS.supports("not foo()")
That returns true
in Firefox (as I'd expect, fwiw), but false
in Chrome and Safari. So you can't use @supports not container(..)
unless they implement the new thing. We should probably get interop on that. My understanding given the supports syntax in https://drafts.csswg.org/css-conditional/#typedef-supports-condition is that this is a Chromium / WebKit bug. Does it match yours @lilles?
Now with that said, in terms of fixing this, yeah, the proposal was on the lines of:
@supports at-rule(<ident>)
To test support for an specific at-rule. @frivoal raised the concern of it being a bit footgunny in cases we extend the syntax of the at rules, so I think this was the most controversial. Then there was:
@supports container(<container-expression>)
And:
@supports media(<media-query>)
And these need specific definitions because <media-query>
has a <general-enclosed>
clause that would parse all media queries successfully (I think this is a mediaqueries-4 feature which we weren't implementing).
My understanding given the supports syntax in drafts.csswg.org/css-conditional/#typedef-supports-condition is that this is a Chromium / WebKit bug. Does it match yours @lilles?
Firefox's behavior is intended to be correct, but I note that @supports does not define what to do with an unknown value that's escaped to the top level (@media does: https://drafts.csswg.org/mediaqueries-5/#evaluating). That needs fixing.
And these need specific definitions because
has a clause that would parse all media queries successfully (I think this is a mediaqueries-4 feature which we weren't implementing).
If you don't implement that, fwiw, then it's not safe for authors to use the new at-rule() or container() or whatever functions, since they'll invalidate the entire rule in older versions. :/
CSS.supports("not foo()")
That returns
true
in Firefox (as I'd expect, fwiw), butfalse
in Chrome and Safari. So you can't use@supports not container(..)
unless they implement the new thing. We should probably get interop on that. My understanding given the supports syntax in https://drafts.csswg.org/css-conditional/#typedef-supports-condition is that this is a Chromium / WebKit bug. Does it match yours @lilles?
I think that foo()
is <general-enclosed>
which is unknown, and not unknown
is unknown, and I couldn't figure out how uknown should be handled.
Hmm, we don't have the "unknown" concept. We just treat all future syntax as unsupported (link). I agree that the spec seems at least weird. Is there an objection of adopting the Firefox behavior here? Anyhow should probably be moved to a separate issue.
My codepen test of a @supports not container(min-width: 0)
block seems to be rendering in both Chrome & Firefox, but not Safari.
It's funny:
Code | Firefox | Chromium | WebKit |
---|---|---|---|
not foo() |
true | false | false |
not foo(bar) |
true | true | false |
not (foo()) |
true | false | true |
not (foo(bar)) |
true | true | true |
So I guess authors can use @supports not (container(min-width: 0))
.
I think that's a fine caveat/hack for authors to ensure better backwards-compatibility, but it would also be good to get these lined up across browsers moving forward. For the sake of future conditions, it would be good for all of these to evaluate as true.
So in my mind we'd be looking for two resolutions here:
container()
function for testing support of specific container-query conditionsThe CSS Working Group just discussed [css-contain] What is the migration path for Container Queries?
.
@tabatkins I think it's essential that @supports
behave different from @media
in this case, because evaluating if new syntax is "known" or "unknown" is the entire purpose of the at-rule – and in many cases "negation" is the most useful test. That is especially true with new at-rules, since they provide their own positive test, and will always require new functional syntax in @supports
.
When we do add new functions to @supports
itself (and I forsee several more functions on the way), we get one of two results:
not foo() == false
), the new syntax gives a false negative in old browsers -- there is no way to write a useful fallbacknot foo() == true
), the new function works as expected everywhere, backwards-compatible in any browser that understands the basics of @supports
-- fallbacks "just work"I don't see how option 1 provides any useful benefit?
Yeah, my original intention was that they should be the same - they both use Kleene 3-value boolean logic, where "unknown" negates to "unknown", and if the whole thing evaluates to "unknown" it is treated as false.
But I see the logic in treating an @supports unknown as just plain false, because the supports queries aren't nuanced choices from equally-likely options, like MQs are. If you don't understand a supports condition, it's likely you don't understand the feature it's testing support for either. (That can be wrong, but it's much more likely to be right than not.) So yeah, it's much more likely to give a correct result if it's just a plain false.
So I agree, we should remove the "unknown" value from supports conditions, and just treat unknown things as false.
The CSS Working Group just discussed [css-contain] What is the migration path for Container Queries?
, and agreed to the following:
RESOLVED: Have unknown @supports expressions evaluate to false for all @support rules
RESOLVED: Create a container function that can test if @supports checks for a particular container query
Not sure why I marked this as not needing edits. The current status seems to be:
container()
function) was not added, but...at-rule()
function [in may](https://github.com/w3c/csswg-drafts/issues/6175#issuecomment-839937577@lilles noted recently that we might want a way to test for style()
queries specifically, before launching that feature. In order to do that, we either need to flesh out the details of a container()
function, or a more powerful variant of the at-rule()
function that allows testing entire rule blocks. My instinct is that we likely want the latter, but maybe that needs more discussion?
This was less necessary for the initial draft of container queries, which can be tested by checking for support of the new properties/values, eg:
@supports (container-type: inline-size) { ... }
Since style queries don't involve any new properties, a more general solution is required.
While at-rules provide their own test for positive support, there is currently no way to test for lack of at-rule support.
With the introduction of media-queries it became common practice to start with a reasonable fallback outside the query, and add progressive enhancement inside the query. That progressive approach also works with some container-queries (see Andy Bell's example), but it falls apart if an author wants to use media-queries as the fallback. Ideally, authors would be able to test for the lack of container-query support, and only apply media-queries when CQ is unsupported (see @eeeps codepen attempt).
If all browsers release 1D containment (or any other new property/value syntax) at the same time as container queries, Eric's approach should work:
It's not likely that any browser would release
@container
before releasinginline-size
containment, but it is possible a browser would release 1d containment first. If that is the only new syntax to test, it could result in some false negatives: browsers that support bothinline-size
&@media
, but not@container
, would miss out on the fallback media-queries. That's not ideal.I think the only way to ensure this migration path works smoothly is to include container-query-specific syntax that can be tested by
@supports
. Theinline-size
value might work for that, but only if browsers are careful to implement both features together.