Re: [csswg-drafts] [css-nesting] Concern about combinatorial explosion (#2881)

The CSS Working Group just discussed `[css-nesting] Concern about combinatorial explosion`, and agreed to the following:

* `RESOLVED: limits on nesting is ua-defined`

<details><summary>The full IRC log of that discussion</summary>
&lt;bramus> TabAtkins: depending on your implentation strategy for nesting and possibly all times, there can be an issue with depely nested style rules<br>
&lt;bramus> … particularly if you have selectorlists<br>
&lt;bramus> … oriol posted an example at the end<br>
&lt;bramus> … crashed webkit and makes style resoltuion take 10s on blink<br>
&lt;astearns> https://yarusome.github.io/box-shadow-proposal/<br>
&lt;matthieudubet> q+<br>
&lt;bramus> … we previously talked about a possible limit<br>
&lt;bramus> .. in practice 3 is a reasonable limit. ppl dont go much further than tat<br>
&lt;bramus> … sass did a survey on it too<br>
&lt;astearns> https://github.com/w3c/csswg-drafts/issues/2881#issuecomment-1642450622 for the latest test<br>
&lt;bramus> … we should spec some reasonable minimum to require and to let browsers have an implementation defined nesting depth<br>
&lt;bramus> … webkit has a limit of 128, but as you can see you can trigger problems much earlier<br>
&lt;bramus> … suggestions to support at least 10 limits, to err on the safe side of what ppl use<br>
&lt;bramus> … max can be higher than that<br>
&lt;fremy> q+<br>
&lt;plinss> q+<br>
&lt;Rossen_> ack matthieudubet<br>
&lt;bramus> matthieudubet: issue is not surely with depths but length of selector<br>
&lt;bramus> … depth limit is easier to explain<br>
&lt;bramus> … real issue here is ???<br>
&lt;bramus> s/???/is the lengths of the context selector<br>
&lt;bramus> … if we put limit, we can put limit on the ??? cotext selector<br>
&lt;bramus> … not depth per se<br>
&lt;bramus> … suggesting to put limit of length on selector list and length of context selector<br>
&lt;emilio> q+<br>
&lt;bramus> TabAtkins: and i think limit would not be a particular complex selector, but in product of nested selector lists<br>
&lt;bramus> TabAtkins: example with 256 * 256<br>
&lt;bramus> … product of lengths of sel lists seems fine<br>
&lt;bramus> … whichever seems more reasonable to impls<br>
&lt;bramus> … we can express a limit that is higher than we expect to see<br>
&lt;bramus> matthieudubet: should we define how we would fail?<br>
&lt;bramus> … support until some depth?<br>
&lt;bramus> TabAtkins: sometimes we do and sometimes not<br>
&lt;bramus> … in this case might make sense to ignore reules that were nested too deeply<br>
&lt;fremy> q-<br>
&lt;fremy> matthieudubet addressed all my points, I think<br>
&lt;Rossen_> ack fantasai<br>
&lt;Zakim> fantasai, you wanted to react to matthieudubet<br>
&lt;bramus> fantasai: if we do a limit on depth, we might all want to have the same limit across vendors<br>
&lt;bramus> … we need to have a min depth that is sufficient for authors<br>
&lt;Rossen_> ack plinss<br>
&lt;bramus> plinss: +1 on limit consistency<br>
&lt;bramus> … concerned about when authors hit it: are they gonna know?<br>
&lt;bramus> … als concerned about of performance impact when we have a reasonable limit. limit can be ??? than we have right now<br>
&lt;bramus> … other issue - dont want to derail - but might make explosion problem worse so will keep for later<br>
&lt;bramus> Rossen_: please introduce<br>
&lt;fantasai> Losing a few rules that are just past the limit in some browsers but not others would be a tle problem that could really break things<br>
&lt;bramus> plinss: when the parent rule has commas with multiple lists, the nested rule is prewrapped in :is() and that breaks the cascade<br>
&lt;fantasai> So we should have interop on nesting depth support if it's not something so far beyond what authors would use that no one will run into it<br>
&lt;bramus> astearns: there is an issue for that<br>
&lt;bramus> emilio: i dont understand<br>
&lt;bramus> TabAtkins: :is() doesnt reflect specificity<br>
&lt;Rossen_> q?<br>
&lt;bramus> plinss: I expect two rules that are nested cascade with different specificyt level,. with :is() you dont have that<br>
&lt;bramus> … explosion is worse than we think it is, if we fix that<br>
&lt;Rossen_> ack emilio<br>
&lt;bramus> emilio: im ok with a limit<br>
&lt;bramus> … i dont think a max should be specced<br>
&lt;bramus> Rossen_: that is what tab suggested<br>
&lt;bramus> … we did sth similar for units way back<br>
&lt;bramus> TabAtkins: but elika was saying we should spec a max<br>
&lt;bramus> fantasai: if the limit is sth low, then it is reasonable atuhors will hit that.<br>
&lt;bramus> … some browsers might then drop rules<br>
&lt;bramus> Rossen_: no, this is about a lower limit<br>
&lt;bramus> fantasai: if the upper limit is far enough – e.g. 100 – only some test cases or autogenerated stuff might hit it<br>
&lt;bramus> … this proposal is that min is 10, but that would mean max can also be 10<br>
&lt;bramus> … min should therefore be far enough to not cause interop prob<br>
&lt;bramus> emilio: we dont have limit of length of selectors.<br>
&lt;bramus> … it all depends on what you are nesting<br>
&lt;bramus> … single selectors nesting is probably fine<br>
&lt;fremy> q?<br>
&lt;fremy> q+<br>
&lt;florian> q+<br>
&lt;bramus> … if you nest lists of 100 selectors each, that might blow up soon<br>
&lt;bramus> fremy: nesting limit does not seem the right metric<br>
&lt;bramus> … correct midway is to see how much selectors you end up with<br>
&lt;bramus> … e.,g. you can have up to 256 if it is expanded<br>
&lt;florian> q-<br>
&lt;Rossen_> ack fremy<br>
&lt;bramus> … better to limit total num of selectors<br>
&lt;bramus> TabAtkins: wont work<br>
&lt;bramus> … at least in blink, if you take oriosl example and wrap it in :is(), you still have a probleme<br>
&lt;bramus> … it is combinatorial in some more ephemral notion of complexity that i do not want to define<br>
&lt;bramus> fremy: that is different<br>
&lt;bramus> … if you put in :is() you only have complexity in running the code, not storing it<br>
&lt;bramus> TabAtkins: blinks performance is the same for with as without<br>
&lt;bramus> … reason we have 10s recompute here is based on sth more intrinsic about complexity of the selector, not the length of the list<br>
&lt;bramus> … a expanded selector here is still 125.<br>
&lt;bramus> … complexity here is not sth we can easily define in terms of any selector metric<br>
&lt;bramus> matthieudubet: if you count list inside of parent list, the time is linear to.<br>
&lt;Rossen_> q?<br>
&lt;bramus> … (missed)<br>
&lt;bramus> .. limit i am suggesting should be related to length<br>
&lt;bramus> TabAtkins: webkit will delay for longer than 10s right now. chrome and firefox have similar timings<br>
&lt;bramus> … but also def of 'what things to expand' is already a number of things: :is(), :where(), :nth-child with of<br>
&lt;bramus> matthieudubet: yes, it is more complex that depth<br>
&lt;bramus> … depth limit of 10 might not be enough<br>
&lt;bramus> TabAtkins: 10 is more then enough for virtually all cases (based on sass survey)<br>
&lt;ntim_> q+<br>
&lt;bramus> … somebody might go over, but in ppl tend to stick below that<br>
&lt;Rossen_> ack ntim_<br>
&lt;bramus> ntim_: i can see limit of 10 being too low, e.g. in build systems<br>
&lt;bramus> myles: what are the curernt limits?<br>
&lt;nicole> q+<br>
&lt;bramus> TabAtkins: none, there is no spec limit.<br>
&lt;bramus> florian: in implementations the run out of memory or crash<br>
&lt;bramus> emilio: yeah<br>
&lt;myles> q+<br>
&lt;Rossen_> ack nicole<br>
&lt;bramus> nsull: can we get data from sass (or some other party) about the number of nmesting authors  do?<br>
&lt;bkardell_> +1<br>
&lt;bramus> miriam: sass does not track that<br>
&lt;bramus> … people nested really deep at the start, but best practice now is 3 but ppl dont always follow that<br>
&lt;bkardell_> surely we can grep github for scss stuff<br>
&lt;bramus> … web archive might have data on that<br>
&lt;bramus> nsull: intersting. what is average selector length?<br>
&lt;bkardell_> ah yeah, good call...<br>
&lt;bramus> Rossen_: if we dotn have the data, we should explore that offline<br>
&lt;bkardell_> q+<br>
&lt;Rossen_> ack myles<br>
&lt;bramus> myles: seems like the limits are purely mechanical<br>
&lt;bramus> … why is this different than things like total number of nodes or nested iframes?<br>
&lt;bramus> TabAtkins: there is a reason why you would want to limit here<br>
&lt;bramus> … if qty is roughly linear with amount of stuff in the page it might be ok<br>
&lt;bramus> … but if its exponentatial we are concerned about it<br>
&lt;bramus> … we have a limit in variables for example<br>
&lt;bkardell_> q-<br>
&lt;bramus> … to prevent doubling in 30 stages before going OOM<br>
&lt;bramus> … this falls in similar case. you dont want ppl to be able to crash a page by writing a crazy selector<br>
&lt;bramus> myles: I understand this is easier here, than a bunch of nested iframes<br>
&lt;bramus> … reason othe rlimits are not standard is bc ppl will not hit them<br>
&lt;bkardell_> q+<br>
&lt;bramus> … are you, tab, saying that reason that limit is needed here bc we expect ppl to make real pages and hit it?<br>
&lt;bramus> TabAtkins: potentially. 3rd party CSS could DOS your page, which is not ideal<br>
&lt;nicole> myles said there are limits on DOM size or number of nested iframes that aren't standardized because they are high enough authors don't hit them<br>
&lt;Rossen_> ack bkardell_<br>
&lt;bramus> bkardell_: 3rd party thing is a little bit tricky<br>
&lt;bramus> … bc 3p stuff could ruin the whole internet<br>
&lt;TabAtkins> i don't mean "a professional company giving 3rd party style", I mean "user-controlled"<br>
&lt;bramus> … i have not seen a ton of sass, but can say that in the stuff i have seen like 4-6 depths is what was there<br>
&lt;bramus> … am happy to help look up the actual numbers<br>
&lt;Rossen_> q?<br>
&lt;bramus> TabAtkins: we do want to have a min limit so that users have an expectation of what is usuable.<br>
&lt;florian> q+<br>
&lt;bramus> … in case of browser limits get cut low<br>
&lt;fremy> q?<br>
&lt;bramus> … we rarely put a max limit<br>
&lt;fremy> q+ (proposal)<br>
&lt;bramus> … but proposed resolution is to add a min limit<br>
&lt;fremy> q- (proposal)<br>
&lt;fremy> q+<br>
&lt;bramus> … it seems like a moderate depth to support<br>
&lt;bramus> … authors might run into a cutoff after that, and uas should make sure pages remain responsive in that case<br>
&lt;bramus> Rossen_: we seem to be circiling back<br>
&lt;TabAtkins> s/moderate depth/moderately excessive depth/<br>
&lt;bramus> florian: for max limit, the can then choose some metric they want?<br>
&lt;bramus> … are browsers likely to create a limit that uathors might hit?<br>
&lt;bramus> … we can also say a limit is implementation defined<br>
&lt;bramus> TabAtkins: analogous situation is size of grids, where we knew that relatively large grids were larger than the limit we had<br>
&lt;bramus> … i am fine with saying it is impl defined<br>
&lt;astearns> implementation-defined and wait for bugs to come in?<br>
&lt;plinss> q+<br>
&lt;bramus> … authors must in that case not do stupid stuff<br>
&lt;Rossen_> ack florian<br>
&lt;bramus> … so i am happy with close no change<br>
&lt;bramus> … currently there is nothing in the spec about it<br>
&lt;Rossen_> ack fremy<br>
&lt;bramus> fremy: quick idea: in the example you can get to 7mo selectors. can we compute the length of th selectors like string length and compute product of that and cut off at a limit?<br>
&lt;bramus> … to prevent expo scenarios<br>
&lt;florian> s/for max limit, the can then choose some metric they want?/for max limit, the can then choose some metric they want, not necessarily depth/<br>
&lt;bramus> TabAtkins: I dont want to get into that complexity bag, and let implementations figure it out<br>
&lt;bramus> fremy: I am proposing to use the actual string length of a selector<br>
&lt;bramus> .. without considering how complex it is<br>
&lt;bramus> … e.g. 1000 chars<br>
&lt;bramus> TabAtkins: problem case here can be constructed in a few 100 chars<br>
&lt;Rossen_> ack plinss<br>
&lt;bramus> plinss: if we allow implementers to choose a limit, then we must set a minimum and have some advice to auhtors about that<br>
&lt;bramus> … to prevent interop issues<br>
&lt;bramus> Rossen_: so back at the same proposal :)<br>
&lt;florian> s/might hit?/might hit? If not, setting a minimum around 10 isn't going to constrain anyone<br>
&lt;bramus> TabAtkins: 2 proposals:<br>
&lt;bramus> … - close no change<br>
&lt;bramus> … - or a depth specified min<br>
&lt;bramus> myles: and a third to pick 10?<br>
&lt;bramus> TabAtkins: that is option 2<br>
&lt;bramus> Rossen_: we seem to come back to option 2<br>
&lt;SebastianZ> I'd vote for option 2.<br>
&lt;argyle> nesting depth `clamp(0, 10, 🤷‍♀️)`<br>
&lt;bramus> fremy: based on tabs remarks option 2 makes no sense? with just adding :is() you can get the same complexitiy in a nmormal selector, so why limit depth in nesting?<br>
&lt;bramus> Rossen_: that is separate issue, no?<br>
&lt;bramus> fremy: it is not<br>
&lt;bramus> astearns: but maybe we should<br>
&lt;florian> q?<br>
&lt;bramus> TabAtkins: it is not just is, is, nthchild, where<br>
&lt;bramus> florian: given that this is a case, should we do nothing nowhere?<br>
&lt;bramus> fremy: that is my point. id rather go with option 1 than 2, as you can do it somewhere else<br>
&lt;bkardell_> q+<br>
&lt;fremy> +1 on Rossen_ proposal to add a recommendation for nesting depth<br>
&lt;bramus> Rossen_: (goes over options again) but happy to go with 1<br>
&lt;SebastianZ> q+<br>
&lt;TabAtkins> Interestigly, if you take Oriol's example, wrap each selector in an :is(), then collapse away the nesting to make it a single selector with the same beahvior, we get substantially faster perf in chrome<br>
&lt;bkardell_> q-<br>
&lt;bramus> plinss: i dont see point in author guidance about exceeding a max, when there is no min in spec<br>
&lt;TabAtkins> (~0.8s on my laptop, vs 13s for the nested version)<br>
&lt;florian> q+<br>
&lt;bramus> Rossen_: (missed)<br>
&lt;bramus> Rossen_: i appreciate the pushback, but dont see how any author guidance for that logic could turn into formal vendor reqs<br>
&lt;bramus> plinss: if we dont have min and give author guidance, that number is ???<br>
&lt;fantasai> +1 plinss<br>
&lt;bramus> Rossen_: perhaps for some browser on some platform<br>
&lt;fantasai> s/???/fiction/<br>
&lt;bramus> plinss: then spec it as min<br>
&lt;Rossen_> q?<br>
&lt;bramus> TabAtkins: even if we consider that. even a small depth might trigger same problem. not certain if that is case or not. there might not be any reasonable metric to use, but reasoanble author behavior with some guideline will keep ppl in bright space of good perf.<br>
&lt;bramus> … trying to lay down a strict limit might not give us the guarantuee of good perf<br>
&lt;emilio> q+<br>
&lt;fremy> @ TabAtkins, if the :is is faster, then your original intuition about the slow down root cause might not be correct, so the issue might not be related to the number of selectors<br>
&lt;matthieudubet> q+<br>
&lt;bramus> … so “you should think about >” might be a good thing<br>
&lt;fremy> @ TabAtkins, I guess maybe we should investigate a bit more<br>
&lt;nicole> q+<br>
&lt;TabAtkins> right, i'm wondering if it's just something about the length of the nesting entirely<br>
&lt;Rossen_> ack SebastianZ<br>
&lt;bramus> SebastianZ: i think a min limit would be good, but<br>
&lt;bramus> .. it is not limited to nesting but also selector complexity so maybe selector spec should also mention that?<br>
&lt;Rossen_> Zakim, close queue<br>
&lt;Zakim> ok, Rossen_, the speaker queue is closed<br>
&lt;bramus> TabAtkins: yeah<br>
&lt;bramus> SebastianZ: if we can come up with a metric, it should be in the selector spec<br>
&lt;Rossen_> q?<br>
&lt;bramus> emilio: since this is related<br>
&lt;bramus> … same case in variable, and vendors have different limits<br>
&lt;bramus> … string based, token based, …<br>
&lt;bramus> … it dont think limit is easy to define<br>
&lt;bramus> … perf is based on impl details<br>
&lt;bramus> … complexity depends on wether elements match too<br>
&lt;bramus> … i would want to leave this undefined until we have decent understanding of these performance characteristics<br>
&lt;plinss> +1 emilio<br>
&lt;emilio> ack emilio<br>
&lt;bramus> Rossen_: by undefined you mean explicitly undef?<br>
&lt;bramus> emilio: yes<br>
&lt;Rossen_> ack emilio<br>
&lt;Rossen_> ack florian<br>
&lt;nicole> +1 emilio<br>
&lt;bramus> florian: I agree, but also give authors some guidance as well<br>
&lt;fremy> +1<br>
&lt;bramus> matthieudubet: as tab said, it does not depend on depth but length of selector which is easy to define<br>
&lt;bramus> … that are the limits we are hitting. not depth, length of selector<br>
&lt;florian> s/guidance as well, but not in terms of max levels, since that's the wrong metric. Rather: "be mindful of combinatorial explosions. For instance {this example} crashes browsers. Don't do this"<br>
&lt;bramus> TabAtkins: a quick test case shows it is not the case<br>
&lt;Rossen_> ack matthieudubet<br>
&lt;bramus> … e.g. 25 :is() is slow<br>
&lt;florian> s/guidance as well/guidance as well, but not in terms of max levels, since that's the wrong metric. Rather: "be mindful of combinatorial explosions. For instance {this example} crashes browsers. Don't do this"<br>
&lt;bramus> matthieudubet: i agree it might be too complex to put into a spec<br>
&lt;Rossen_> ack nicole<br>
&lt;bramus> nsull: agree with emilio and myles<br>
&lt;bramus> … we dont know how devs will use this<br>
&lt;bramus> … making up guidance now seems too premature<br>
&lt;bramus> … so I support option 1, and see what actually breaks now<br>
&lt;bramus> … and we might revisit guidance later<br>
&lt;bramus> myles: I was not stating, but asking for clarification<br>
&lt;astearns> ack fantasai<br>
&lt;bramus> Rossen_: seems like there is enough support for option 1 to keep it explicitly undefined<br>
&lt;bramus> … it is important that impls not crash though<br>
&lt;bramus> … can we resolve?<br>
&lt;TabAtkins> Also I misremembered, Variables does *not* impose an explicit limit, it just calls this out as an impl issue.<br>
&lt;bramus> plinss: small objection, as option 1 was 'close no change' and wait for data<br>
&lt;bramus> TabAtkins: I am fine with 'close no change' without prejudice<br>
&lt;bramus> … untill we hit a problem in the future<br>
&lt;bramus> ntim_: we need to figure out how nesting is used in the wild<br>
&lt;bramus> Rossen_: so are you signing up?<br>
&lt;bramus> ntim_: no<br>
&lt;bramus> TabAtkins: bug trackers will find the data, and then we can file a new issue based on that<br>
&lt;florian> +1<br>
&lt;bramus> … until we have practical proof, we dont need to hold this open<br>
&lt;bramus> iank_: we had a limit for grid tracks, and we received a bunch of bugs for it. so ppl file them<br>
&lt;bkardell_> Can I ask for one clarification? Is option #1 also put no author guidance/information about preventing problems into the spec?<br>
&lt;bramus> ntim_: to prevent interop issues, we need the data<br>
&lt;bramus> TabAtkins: and the bug reports will surface that<br>
&lt;bkardell_> Rossen_: ^ can we clarify that?<br>
&lt;bramus> Rossen_: lets close here<br>
&lt;TabAtkins> this issue has no bearing on author guidance in the spec<br>
&lt;TabAtkins> I'll put some in.<br>
&lt;bramus> … do we want to resolve on 1: explicitly define that the limit is (pause) undefined<br>
&lt;bkardell_> if tab will put some explanation in, I can +1 on option 1<br>
&lt;bramus> Rossen_: objections?<br>
&lt;bramus> plinss: no<br>
&lt;bramus> Rossen_: explicilty undefined as in “no limit”<br>
&lt;TabAtkins> i'll put in some guidance similar to this https://drafts.csswg.org/css-variables/#long-variables<br>
&lt;bramus> plinss: we will have answer when research is done<br>
&lt;bramus> Rossen_: objections?<br>
&lt;bramus> florian: saying explicitly that there is no limit, you require ???<br>
&lt;bramus> TabAtkins: no, not 'no limit' but undefined<br>
&lt;bramus> … proposed resolution: nesting limit is UA defined<br>
&lt;TabAtkins> proposed resolution: limits on nesting is ua-defined<br>
&lt;bramus> RESOLVED: limits on nesting is ua-defined<br>
</details>


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


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

Received on Wednesday, 19 July 2023 21:41:12 UTC