-
Notifications
You must be signed in to change notification settings - Fork 687
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[css-conditional-5][css-nesting-1] Feature detection for nesting #8399
Comments
Maybe the simplest solution would be to reuse the So this could detect whether nesting style rules is supported: @supports selector(& .foo) {
…
} Though that only covers style rules. Support for nesting other rules like media queries might require a different approach. One solution would be to support testing of complete rules, as I suggested earlier. An example of that could look like this: @supports (.foo { @media (width >= 500px) { } }) {
…
} Another, more flexible but also more complex approach would be script based queries, which I also suggested earlier. Sebastian |
I highly doubt authors will use something like @supports selector(& .foo) {
.wrapper {
color: magenta;
& .foo { color: cyan; }
}
}
@supports not selector(& .foo) {
.wrapper { color: magenta; }
.wrapper .foo { color: cyan }
} They will just use the good ol .wrapper { color: magenta; }
.wrapper .foo { color: cyan } The only reasonable fallback strategy seems using JS to read the raw contents of the function supportsCSSNesting() {
try {
document.querySelector("&");
return true;
} catch (e) {
return false;
}
} Support for nesting other rules like media queries is also posssible: var style = document.createElement("style");
style.textContent = ".foo { @media (width >= 500px) { } }";
document.head.append(style);
var {sheet} = style;
style.remove();
return sheet.cssRules[0]?.cssRules?.length === 1; We may want to add nicer ways, but I don't think it's a must. |
I agree that authors will likely not write single stylesheets with both nested and un-nested versions of selectors. They'll either, as you say, write the stylesheet without nesting until they no longer care about older browsers, or use a preprocessor and let it emit the un-nested version. However, what's reasonable, and should be encouraged, would be: @import "nested-and-small.css" supports(selector(&));
@import "not-nested-and-large.css" not supports(selector(&)); (or ideally do the equivalent in <link> tags) This way the author can use a preprocessor to generate the larger, un-nested stylesheet, but the user of a newer browser doesn't have to pay the download cost. While nesting should be detectable via script, we need to be able to feature detect it without script (or UA sniffing) as well. |
@plinss I totally agree with what you say and also thought of the usage in @Loirooriol Relying on JS to solve this is also one of my ideas from above, though ideally JS shouldn't be a requirement for feature detection. If testing for Though being able to test for other nesting features is still important. So there's no gap between implementations and feature detectability. Sebastian |
@import "nested-and-small.css" supports(selector(&));
@import "not-nested-and-large.css" not supports(selector(&)); No browser has implemented this (yet?) |
Sure, but no browser has really implemented nesting yet either (STP and Chrome experiments not withstanding). The WG hasn't resolved on the actual mechanism to feature detect nesting yet either, the above was a (reasonable) placeholder. Given there are still open questions on the final syntax of nesting it doesn't make sense to finalize the feature detection yet. I expect that the WG will finalize how to feature detect nesting when we finalize nesting itself, and any browser implementing nesting will implement the feature detection at the same time (it should be part of a compliant implementation). |
@plinss In case you are not aware of it, Blink plans to ship the "experiment" in version 112. https://groups.google.com/a/chromium.org/g/blink-dev/c/eFCrkiLynfU/m/JLsh3zQuAAAJ |
This is a tangent and I don't want to derail this thread but In theory it is the best method, but because it never shipped it isn't practically useful. html sample to illustrate the issue<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
/* Red */
@import url(data:text/css;base64,Ym9keSB7IGNvbG9yOiByZWQ7IH0=);
/* Cyan */
@import url(data:text/css;base64,Ym9keSB7IGNvbG9yOiBjeWFuOyB9) supports(selector(&));
/* Purple */
@import url(data:text/css;base64,Ym9keSB7IGNvbG9yOiBwdXJwbGU7IH0=) not supports(selector(&));
</style>
</head>
<body>
Always red, never purple.
</body>
</html> |
I'm aware, unfortunately just another example of Google (potentially) being Google and deciding that they know best without allowing the standards process to come to a determination of a mutually agreed best path forward. Then leveraging their market dominance to try to establish a de-facto standard. (And Apple isn't much better in their messaging around STP). |
@plinss I would like to ask you to revisit this comment. We are here, participating in the standards process. The web standards process is not now, nor has it ever been, a gate that controls features that are shipped in implementations. At the same time, as a large engine implementer, we have a responsibility to participate in good faith to build consensus on features; I believe we are doing that here. If you disagree, as per our policy (https://github.com/cwilso/standards-of-behavior), I'm happy to discuss in more depth. |
@cwilso I edited my comment to remove the phrase that you found offensive. However, while I agree that Google is here, and is participating, I fail to see how shipping a feature in a form that is still under contention and discussion can be characterized as "participating in good faith". You are of course free to ship whatever you want, but you don't get to characterize paving your own path as a "standards process". Your Blink dev thread makes it clear that your shipping decision process isn't waiting for this issue to be resolved by the WG, let alone an FO. |
I guess what we can agree on is that browser vendors are eager to release these nesting capabilities. Sebastian |
@romainmenke Very good point! So it seems that we need a different approach so that UAs with nesting support can block loading stylesheets and rules without nesting to avoid loading them twice in that case. Sebastian |
I’ve tested several approaches in the past:
The caveat with approach 2 is that it assumes a browser does not ship In practice, though, I don’t think authors will test nesting, as they’ll simply see the nested styles not get applied in that case:
|
For I've created a pull request with a basic WPT test : web-platform-tests/wpt#38373 Currently Chrome and Safari TP do not support Edit : there was already a test added recently : https://wpt.fyi/results/css/css-nesting/top-level-is-scope.html?label=master&label=experimental&aligned&view=subtest&q=nesting |
Even before this, I believe |
It does indeed work, but the question here is if This approach is only viable if browsers ship nesting and " |
See comment above:
It is the obvious/logical thing to do, but maybe it can also be enforced from within the spec? |
Seems too late, Blink shipped |
Yeah, I assumed we wouldn't ship the nesting selector separate from the nesting feature, as it was useless on its own and provided a nice benefit to feature detection. Ah well. |
Blink shipped & together with nesting support. The commit you're linking to (which did indeed add nesting and & at the same time, but the version that was current at the time) was all behind an experimental flag; it would not do anything in a normal, stable browser. |
I bisected without experimental flags and I got that commit. And effectively with the stable 109.0.5414.119 snap I can see that |
That definitely wasn't the intention of the code, but OK, it's impossible to back and change now. |
That was fixed in https://bugs.chromium.org/p/chromium/issues/detail?id=1414012 and backport requested to Chrome 111. (Thanks @sesse!) |
But impossible to backport to 109 and 110 right? |
Correct, we can't fix existing versions in the wild. (Or rather, we reserve that sort of thing for OMG THE WORLD IS ON FIRE security issues.) But Chrome versions decay in usage quickly. |
(Cross-posting from Chromium’s I2S) Authors can work around Chrome 109+110 incorrectly reporting @supports selector(&) and (scale: cos(90deg)) {
…
} This check excludes Chrome 109+110, but includes Chrome 111 with the feature flag on. More importantly this extended check won’t exclude Safari or Firefox, as they too support |
To be honest, feature detection here is less likely to affect users migrating to native nesting, instead, I think the more fatal problem is the desugaring to |
This was revisited here : #8310 |
I suspect once Nesting has critical mass, what will be more common would be this pattern: HTML: <link rel=stylesheet href="nested.css"> nested.css: @import "compiled-to-nonnested.css" not supports(selector(&));
/* nested CSS */ |
This doesn't work, it was never implemented. see : #8399 (comment) |
There is also no way to detect support for the even more relaxed syntax where selectors can start with an identifier. In Chrome 113 : CSS.supports('selector(& bar)')
// true
CSS.supports('selector(bar &)')
// true Safari TP doesn't seem to work at all : CSS.supports('selector(&)')
// false
CSS.supports('selector(& bar)')
// false
CSS.supports('selector(bar &)')
// false This seems problematic if the plan is to relax the syntax somewhere in the future. |
Hmm, that looks like a bug to me, given Safari TP does support that selector. Searching the WebKit bug tracker, I found this bug filed for it: https://bugs.webkit.org/show_bug.cgi?id=252301
If one could nest inside of CSS.supports('selector(div { span })'); I think this shortcoming should be plugged. |
Chrome is shipping nesting in ±2 weeks. Especially : #8399 (comment)
|
The CSS Working Group just discussed The full IRC log of that discussion<fantasai> astearns: Something shipped in Chrome that's not quite what we want, but not clear on what we want<fantasai> ... we should have had a good story before shipping anything <fantasai> TabAtkins: I agree that this being parsable before shipping was ready was a mistake, but I don't think we can fix retroactively <fantasai> ... don't think we should expose whether nesting is possible or not <fantasai> astearns: we shouldn't have feature detection? <fantasai> TabAtkins: we shouldn't add anything except selector detection, it'll just misfire on some versions of Chrome/Safari <fantasai> plinss: wasn't there discussion of using & in other places? <matthieudubet> q+ <fantasai> TabAtkins: allowing it elsewhere, yes, but concurrent with Nesting being supported <fantasai> plinss: is that guaranteed? <fantasai> TabAtkins: In practice yes <fantasai> plinss: but it's usable in another feature that's not dependent on Nesting <fantasai> TabAtkins: only @scope, but it's also nesting rules ... <emeyer> fantasai: That’s different from the nesting feature because @scope can only contain nesting rules <fantasai> TabAtkins: don't think ti's a problem in practice <astearns> ack matthieudubet <fantasai> matthieudubet: for feature detection, should we try to give the proper result with a selector <fantasai> s/selector/relative selector/ <fantasai> matthieudubet: should @supports be aware of the nesting stack? <plinss> q+ <fantasai> matthieudubet: and always return true/false regardless of nesting stack? <fantasai> TabAtkins: the latter. @supports shouldn't be aware of where it is in the stylesheet <TabAtkins> .foo { @supports selector(&) {...}} <fantasai> TabAtkins: that should not give different results at the top level vs nested <fremy> .foo { @supports selector(+a) {...}} <fantasai> matthieudubet: & is allowed both places, but relative selectors are allowed or not depending on whether nested <fantasai> TabAtkins: I would prefer we don't make @supports context-sensitive <fantasai> TabAtkins: right now we don't carry context into the querying APIs, and you can't express that in JS <fantasai> ... so as much as possible I'd like to keep those consistent <fantasai> matthieudubet: Right now for Safari, it does take context into account <fantasai> ... so if the selector is not supported *there* it'll return false <TabAtkins> CSS.supports() <fantasai> TabAtkins: what about CSS.supports()? <fantasai> TabAtkins: the JS API can't know the context <fantasai> matthieudubet: That's what we do for the at-rules. For JS API, we do the same, so when you write a relative one will always say false <fantasai> ... because not in a nested context <fantasai> TabAtkins: that interpretation is novel, and not expressed in the spec right now <fantasai> ... if we want to do that, can you raise an issue? <fantasai> ... new issue, please; this is unrelated to the current issue <fantasai> astearns: It's better to have specific issues on narrow problems <astearns> ack plinss <fantasai> ... so agree we should have a separate issue on whether relative selectors inside @supports are context-sensitive <fantasai> plinss: Important that nesting be readily detectable at the top level <fantasai> ... I have concerns about feature detection of one feature being dependent on another feature <fantasai> ... just because we implemented & and nesting together is cute, but not something to rely on <emilio> But agreed nesting should def. be detectable in top-level and CSS.supports <fantasai> fremy: If you want o feature-detect @scope, how do you do it? <fantasai> plinss: how do I detect & for @scope? <fantasai> TabAtkins: at-supports API doesn't yet allow querying that sort of thing <fantasai> plinss: we need reliable support detection for nesting, that works reliably for @import supports(). <fantasai> ... so & detection is not good enough <fantasai> TabAtkins: currently can only express as selector(&), if you want something more specific need a new thing <fantasai> plinss: that needs to ship with Nesting <fantasai> astearns: any suggestion of what this might look like? <fantasai> plinss: @nest? <fantasai> fremy: how about we check whether & is a valid property? That would be checking for nesting <fantasai> ... e.g. @supports (&) { ... } <heycam> @supports rule(p { & { } }) <fremy> @supports (&{}) <bradk> @supports (nesting) { … } <fantasai> TabAtkins: that's not valid property <fantasai> TabAtkins: maybe not that bad given how messy the shipping has been with this feature, but in general want to avoid special casing <fantasai> plinss: We might want a general feature() function for things that are hard to feature-detect <emeyer> fantasai: I think Francois’s suggestion does fit the current syntax <emeyer> …That said, if we do allow that, we’ll be allowing any kind of selector-based rule that can be nested to be in there <emeyer> …Might be more parsing than we want, but not inconsistent <fantasai> TabAtkins: Depends if you think of it as () parses a declaration or if () parses "stuff that could go in a declaration block" <fantasai> plinss: Would be a problem if we allow selectors, since range of selectors is open-ended <fantasai> ... what if we add a div property <fantasai> fremy: same problem we have today already <fantasai> fremy: To me, I think it's a nice extension, doesn't require a big change <fantasai> ... not saying we have to do it, it's just an idea <fantasai> TabAtkins: can we do the rest of the design work in the thread? we have 9 min on the most important isseu <fantasai> astearns: Sounds to me that for this issue, we're going to retain the bare & supports strategy in the spec, but might also add something that is a little more complex or specific? <fantasai> TabAtkins: think so <fantasai> astearns: so leave discussion here, don't need a resolution since selector(&) aready works <fantasai> ... but will leave this issue open for further discussion of supports functionality <fantasai> plinss: I believe it's very important that we have a stable and reliable mechanism before we ship anything, can we agree on that <fantasai> TabAtkins: I think it's a good idea, I'm not going to commit to it <fantasai> plinss: I think shipping this whithout reliable feature detection is a huge mistake <fantasai> +! <fantasai> +1 <fantasai> astearns: agree with plinss <emeyer> +1 <bradk> Me too <fantasai> astearns: I think we should have another breakout on Nesting next week |
I totally agree with @plinss here. I fear, Google's strategy for shipping nesting without proper support for feature detection will have negative effects. Without a proper mechanism for feature detection, nesting is doomed to either not being adopted or to cause pages to break. As @romainmenke pointed out earlier, the main issue is that browsers never implemented
As outlined above, layering nested styles on top of not nested ones is not really a use case. Authors normally want to apply the same rules independently of how they are written. Coming back to the issue outlined by @romainmenke, I believe, the main issue is allowing nesting while being backwards compatible and avoid putting the burden onto users. Sebastian |
I like @heycam’s suggestion here to be able to pass an entire rule-set into This would help not only here with nesting, but also cover future/other CSS features such as This extension to This extension to |
It wasn't a pre-release version of Chrome that incorrectly claimed to support There also isn't a way to differentiate between what shipped in Chrome 112 and the highly likely direction of the specification : // In Chrome 112
CSS.supports('selector(&)')
// true
CSS.supports('selector(& div)')
// true
CSS.supports('selector(div &)')
// true Ideally authors have a reliable way to detect support for the final version of nesting, even in older versions of Chrome. |
If more robust/reliable feature detection through < method-this-issue-settles-on > lands, Chrome 112 wouldn’t support that new detection method, so it would still get the non-nested styles because it has a more limited nesting support. Rewinding a bit. Say the suggested @import "nested-and-small.css" supports(<method-to-detect-nesting>);
@import "not-nested-and-large.css" not supports(<method-to-detect-nesting>); That means, the snippet above won’t cut things here:
What is parseable is, is this … but then you’d end up with double loads + competing stylesheets in browsers that do support @import "not-nested-and-large.css";
@import "nested-and-small.css" supports(<method-to-detect-nesting>); Not sure how this could be solved in a nice way 🤔 |
Correct, although browsers do download all stylesheets, even when they ignore them. Some browsers maybe don't intend to ship nesting support in the sort term. It doesn't help all users of older browser versions but it might still be a useful tool. |
The CSS Working Group just discussed The full IRC log of that discussion<fantasai> astearns: We have a feature-detection story, question is how to detect browsers that support nesting vs don't support nesting?<dbaron> astearns: Is that what's remaining in this issue? <fantasai> TabAtkins: unsure... someone else should take this <fantasai> SebastianZ: We need some way to migrate and have fallbacks for old browsers <fantasai> SebastianZ: so the question is how to allow feature-detection, and at the same time do it so that all the browsers don't fail completely <fantasai> SebastianZ: Of course they don't support nesting, but we need some way to handle that case <fantasai> ???: We need more than just selector(&)? <dbaron> s/???/matthieu/ <astearns> s/???/matthieu/ <fantasai> SebastianZ: selector(&) does work, but it focuses on style rules. Doesn't target whether other rules can be nested, or media rules, or something else <fantasai> astearns: Given that we have not much time yet, does it make sense to continue the discussion of this upgrade strategy in this issue, or should there be a separate issue just on the path we want authors to take when they don't know whether the browsers supports nesting or not? <fantasai> SebastianZ: I think there's an issue targetting the author experience... not sure which one it was <fantasai> astearns: Since this feature is titled Feature Detection, should we close this issue and find or create an issue about the author experience? <fantasai> SebastianZ: Hard to say <fantasai> SebastianZ: you want feature detection for author so that they can migrate to nesting, so they're both entangled <fantasai> ACTION: astearns to find path forward for this author-experience issue, whether to continue with this issue or make a new one |
Summarizing the remaining parts:
The first poing still directly refers to this issue. For the second point I can create a separate issue. Sebastian |
We need to provide a smooth way to transition to nesting, so authors can detect whether nesting is supported by the user agent. So they can provide fallback solutions for UAs that don't support it.
There where already some prior discussions related to this topic, though no explicit issue or resolution regarding this, as far as I can tell.
The major discussion related to this is #8349, but its focus is rather on error recovery than feature detection. Another slightly related one is #2463, though it rather features detection of at-rules and their descriptors.
So I opened this issue to explicitly discuss how nesting support can be made detectable. I believe this is a must for any implementation for shipping nesting capabilities to reach a high level of adoption and avoid page breakages.
Sebastian
The text was updated successfully, but these errors were encountered: