Re: [csswg-drafts] [css-nesting-1] Clearer definition of “nest-containing” (#7972)

The CSS Working Group just discussed `Clearer definition of "nest-containing"`, and agreed to the following:

* `RESOLVED: Relative-ness is decided based on & appearing *anywhere* in the selector, even nested inside anything else`
* `RESOLVED: Option 2`

<details><summary>The full IRC log of that discussion</summary>
&lt;fantasai> Subtopic: Clearer definition of "nest-containing"<br>
&lt;fantasai> github: https://github.com/w3c/csswg-drafts/issues/7972<br>
&lt;dbaron> Zoom for web is not working for me... I've tried multiple browsers at this point.<br>
&lt;dbaron> (doesn't work in either Chrome or Firefox)<br>
&lt;fantasai> TabAtkins: If a selector starts with a combinator, we assume relative selector<br>
&lt;fantasai> TabAtkins: insert &amp; and interpret accordingly<br>
&lt;fantasai> TabAtkins: If no such combinator, we need to check if this should be relative selector or if there's an &amp; deeper in<br>
&lt;fantasai> TabAtkins: Could have something like "foo &amp;" or ":not(&amp;) ..>"<br>
&lt;fantasai> TabAtkins: But spec is not super clear what it means by "contain" an &amp;<br>
&lt;TabAtkins> :is(&amp;:unknown, .foo)<br>
&lt;fantasai> TabAtkins: e.g. what happens if &amp; is inside :is() within branch that's ignored by invalidity?<br>
&lt;fantasai> TabAtkins: is that &amp;-containing or not?<br>
&lt;fantasai> TabAtkins: Depending on our answer, how does it affect serialization<br>
&lt;fantasai> TabAtkins: Listed a few options<br>
&lt;fantasai> TabAtkins: 1. Only look at top-level, not inside parens<br>
&lt;fantasai> TabAtkins: 2. Look everywhere except inside forgiving parsing list<br>
&lt;fantasai> TabAtkins: 3. Get deeper into parsing guts, say something about &amp; inside even forgiving selector lists that might be invalid, and preserve that info across serialization even though normally drop such branches during reserialization<br>
&lt;fantasai> TabAtkins: fantasai and I thought #3 would be weird, because [missed]<br>
&lt;fantasai> TabAtkins: so initial suggestion was #1, simple suggestion<br>
&lt;fantasai> TabAtkins: after discussion with Natalie and Miriam, there were too many use cases for &amp; deeper than top-level<br>
&lt;fantasai> TabAtkins: and having selector only in one branch and not others is weird and unusual, so not that important if behavior differs in branches<br>
&lt;dbaron> OK, given that the meeting link doesn't work for me in (a) Chrome/Mac (b) Firefox/Mac, and (c) Firefox/Linux, I'm going to give up for technical difficulties... see you at the regular call in 50 minutes.<br>
&lt;fantasai> TabAtkins: so suggestion is to look for &amp; in every branch, invalid or not<br>
&lt;fantasai> TabAtkins: needs authors to be a little more careful<br>
&lt;fantasai> TabAtkins: but simple: if there's an &amp; anywhere, it's got one<br>
&lt;fremy> q+<br>
&lt;fantasai> TabAtkins: Might need to tighten up parsing by having known-invalid selectors serialize as something particular<br>
&lt;fantasai> TabAtkins: So definition proposed is that it's containing an &amp; if it contains an &amp; anywhere<br>
&lt;fantasai> fremy: Tab mentioned that it's weird to have branches where some contain &amp; but some do not<br>
&lt;fantasai> fremy: I agree, if you're doing that it's probably a mistake<br>
&lt;fantasai> fremy: But then why can't we make this a rule?<br>
&lt;fantasai> fremy: if you have a branching selector, have to have &amp; in every branch<br>
&lt;dbaron> (ok, zoom started working when I clicked on the grayed-out "More ..." button at the bottom)<br>
&lt;fantasai> fremy: otherwise invalid<br>
&lt;fantasai> TabAtkins: Valid question, we could, but probably doesn't matter because unusual case<br>
&lt;fantasai> TabAtkins: so I don't think it's necessary<br>
&lt;fantasai> TabAtkins: but I could do either way<br>
&lt;Rossen_> ack fremy<br>
&lt;fantasai> fantasai asks for an example<br>
&lt;fantasai> TabAtkins: Consider the previous example, where only one branch of :is() has an &amp;. Difference is we'd make that illegal<br>
&lt;TabAtkins> so `:is(&amp;:unknown, .foo)` would be an invalid selector<br>
&lt;fantasai> TabAtkins: Also weird, it would be the only way for :is() to invalidate a selector<br>
&lt;lea> in case it helps, as an author, I'd expect .foo { :is(&amp;, .bar) {} } to be interpreted as .foo, .foo .bar , not .foo, .bar<br>
&lt;fantasai> TabAtkins: another little bit of complexity that we could avoid for a corner case<br>
&lt;fantasai> fremy: Yes, I think I agree. It might not make much sense, but you might want it<br>
&lt;fantasai> TabAtkins: Lea posts a different suggestion, which is that you take different paths in deciding relative selector or not<br>
&lt;fantasai> TabAtkins: Problem is that doesn't map directly to :is() notation, so suspect it would complexify implementations<br>
&lt;chris> leaverou there was a question for you<br>
&lt;fantasai> fantasai: Do we have any comments from implementers on lea's question?<br>
&lt;lea> chris: what was it? I'm looking at the minutes but can't find it. I'm not on the call, as I'm on the TAG plenary<br>
&lt;fantasai> TabAtkins: I can't say for sure, but I think  our implementation would find it difficult<br>
&lt;fantasai> s/sure/sure because our implementers aren't on the call/<br>
&lt;fantasai> emilio: Doing what Lea suggests would be fairly annoying<br>
&lt;fremy> @ lea, the question was whether TabAtkins's reply to you addressed your concern or not<br>
&lt;fantasai> emilio: and could have problems with selectors growing exponentially, which is not great<br>
&lt;fantasai> emilio: I think this is a problem Blink had when they initially implemented this<br>
&lt;fantasai> TabAtkins: When trying to do naive impleementation of :is(), it was a problem<br>
&lt;fremy> @ lea, and (I guess) whether this was something you felt strongly about<br>
&lt;lea> fremy: no, this is not something I feel strongly about<br>
&lt;fantasai> Rossen_: Current proposal is simply option 3 without any further modification (and by option 3 we mean option 3 in IRC, which is option 2 in the issue)<br>
&lt;TabAtkins> proposed resolution: Relative-ness is decided based on &amp; appearing *anywhere* in the selector, including in (potentially-invalid) branches of a forgiving-selector-list<br>
&lt;fantasai> plinss: I presume it's only legal for one &amp; in selector?<br>
&lt;fantasai> TabAtkins: no can have multiple<br>
&lt;fantasai> plinss: so I can say &amp;.foo &amp;.bar?<br>
&lt;lea> though I do find it fairly weird if you can "break" out of the nest by doing `:is(&amp;, .bar)`. and if :is(.bar) matches different things than the .bar in :is(&amp;, .bar)<br>
&lt;fantasai> TabAtkins: &amp; represents elements matched by the parent selector<br>
&lt;fantasai> TabAtkins: would be two different elements that both happen to match the same parent<br>
&lt;fantasai> plinss: fair enough<br>
&lt;Rossen_> ack fantasai<br>
&lt;TabAtkins> fantasai: suggest we clarify that if I have any kind of selector garbage inside :is(), including an &amp; nested deep inside of the garbage, that &amp; is considered to be an &amp; for these purposes?<br>
&lt;TabAtkins> TabAtkins: correct<br>
&lt;fantasai> :is(:unknown(&amp;))<br>
&lt;fantasai> :is([something (&amp;something else { } ) ])<br>
&lt;TabAtkins> :is([{(&amp;)}]) has an ampersand in it, per the suggested resolution<br>
&lt;fantasai> TabAtkins: If during selector parsing you see an &amp; delim token, mark the selector as having an &amp; and continue normal parsing<br>
&lt;fantasai> Rossen_: any other feedback?<br>
&lt;fantasai> RESOLVED: Relative-ness is decided based on &amp; appearing *anywhere* in the selector, even nested inside anything else<br>
&lt;fantasai> TabAtkins: Question is what to do about serialization<br>
&lt;fantasai> TabAtkins: Option 1: do nothing special. This might mean that an invalid branch is dropped, which changes selector interpretation<br>
&lt;fantasai> TabAtkins: Option 2: serialize any :is() branch that contains an &amp; as-is<br>
&lt;fantasai> TabAtkins: Option 3: serialize any :is() branch that contains &amp; as something guaranteed to be invalid, e.g. "&amp;:not(&amp;)" (which is guaranteed to not match but definitely contains an &amp;)<br>
&lt;emeyer> q+<br>
&lt;fantasai> emilio: Only doing ????<br>
&lt;fantasai> TabAtkins: Option 4: do 2 or 3 if that's the only branch that contains an &amp; (and thus the selector interpretation is dependent on that branch existing)<br>
&lt;Rossen_> ack emeyer<br>
&lt;fantasai> emeyer: wrt option 1, what are the concerns?<br>
&lt;fantasai> emilio: It's bad if something serializes and then whe you re-parse it it's interpreted differenly than the original<br>
&lt;fantasai> TabAtkins: So you can have a selector that's relative in new browsers and non-relative in older browesers, which is significant change<br>
&lt;fantasai> emilio: You lose the forgiveness ... which is annoying<br>
&lt;fantasai> [missed]<br>
&lt;dbaron> My preferences:  definitely not option 1, weakly prefer option 3 (without the option 4 variant).<br>
&lt;fantasai> emilio: Implementationwise, it feels like it would be nice not to account for &amp; in invalid branches, so you can compute the relativeness of a selector independently of the parsing process<br>
&lt;fantasai> &lt;fantasai> +1 dbaron<br>
&lt;fantasai> emilio: ... but all the options are weird in their own way<br>
&lt;Rossen_> q?<br>
&lt;fremy> @ TabAtkins, for option 3 `&amp;:not(&amp;)` might be costly to compute, how about something truly invalid like `::-invalid-(&amp;)`<br>
&lt;fantasai> [Tabatkins summarizes dbaron's comment into audio]<br>
&lt;fantasai> plinss: [asks about option 2]<br>
&lt;fantasai> emeyer: option 2 is consistent with media queries, where we preserve the CSS string for general enclosed<br>
&lt;fantasai> TabAtkins: fair<br>
&lt;emilio> s/emeyer/emilio<br>
&lt;fantasai> [Leaning towards 2 or 3]<br>
&lt;dbaron> I'm also fine with 2.<br>
&lt;fantasai> Straw Poll: Option 2 vs Option 3<br>
&lt;TabAtkins> abstain<br>
&lt;fantasai> abstain (defer to implementers)<br>
&lt;emilio> either wfm<br>
&lt;plinss> 2<br>
&lt;lea> 2 (based on the descriptions in the comment primarily, as I've missed a lot of the discussion due to being on another call)<br>
&lt;Rossen_> 3, 2<br>
&lt;fremy> abstain<br>
&lt;emeyer> abstain<br>
&lt;chris> abstain<br>
&lt;davidleininger> 2<br>
&lt;dbaron> abstain<br>
&lt;florian> abstain<br>
&lt;jensimmons> abstain<br>
&lt;fantasai> emilio: other issue of option 2 is that it changes behavior from today<br>
&lt;fantasai> TabAtkins: in theory, yes, if someone is putting &amp; inside their invalid :is() selector, it will change serialization<br>
&lt;fantasai> emilio: We probalby want to do it for all invalid selectors, so that :unknown is reserialized as-is, regardless of &amp;<br>
&lt;fantasai> TabAtkins: I suggest taking up separately<br>
&lt;fantasai> Proposed to go with option 2<br>
&lt;fantasai> and emilio to open issue about switching serialization for all selectors<br>
&lt;fantasai> plinss: In my mind, would want to be consistent for all selectors<br>
&lt;fantasai> TabAtkins: I agree in theory, don't care too much<br>
&lt;fantasai> RESOLVED: Option 2<br>
&lt;fantasai> TabAtkins: open separate issue for the rest, because it may have a compat risk<br>
&lt;fantasai> plinss: If the other one goes the other way, might want to revert this one<br>
&lt;fantasai> TabAtkins: currently don't have compat either way for &amp; stuff<br>
&lt;fantasai> plinss: Yes, but I want us to note in the other issue to reconsider this one<br>
&lt;emilio> I can open the issue<br>
&lt;fantasai> ACTION: emilio to open new issue<br>
</details>


-- 
GitHub Notification of comment by css-meeting-bot
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/7972#issuecomment-1403898638 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Wednesday, 25 January 2023 16:35:49 UTC