`restructureRules` can hit the limit of max number of selectors per rule
See original GitHub issueI’m using clean-css
4.0.9 through the command-line (cleancss -O2 'all:off;restructureRules:on' test.css -o test.min.css
). I’m on Ubuntu 16.04.
When using restructureRules
, all rules that share the same body are grouped under the same list of selectors, as expected. But it seems that Chrome has a limit on the number of selectors you can put in one rule. From my empiric testing, it seems to be around 8192 items (the length of the selector has no impact, only their count). If you have more than that, the selectors are simply ignored.
I’m not sure if this is a clean-css
or a Chrome bug, but as clean-css
is already handling the quirks of several browsers, I thought it was worth submitting as an issue.
To demonstrate it, I’ve created a file with a rule that contains 8192 selectors, and an HTML file with a single #test
id.
#h1 { background: green; }
#h2 { background: green; }
[...]
#h8190 { background: green; }
#h8191 { background: green; }
#test { background: green; }
<div id="test"></div>
It works, and the div
is correctly displayed as green. But if I convert it through clean-css, I got the following file as a result:
#h1, #h10, [...], #h999, #test { background: green; }
#h201 { background: green; }
(You can note that there are actually two rules, the second one containing only one selector that seems random. I don’t know if it’s related or not.)
If you test this file in your Chrome, the div
is no longer green, the rule is completly ignored. If you remove one selector from the list, then it’s working again. The solution would be to always keep the list of selectors in a rule under the threshold (you can have two rules, with the exact same declarations, with 8190 selectors each and it will work fine).
I know that in the real world, you’re not supposed to have that many selectors in the same rule, but the project I’m working on actually have them (for good reasons), and being able to minify it would considerably reduce the file size. If not for this limitation.
Happy to provide more insights/tests if needed.
Issue Analytics
- State:
- Created 7 years ago
- Comments:32 (5 by maintainers)
Top GitHub Comments
So it’s fixed on master ^ - I’ll backport it to 4.0 with the fixed limit.
This selector contains 9 simple selectors and takes up 9 slots in the selector structure:
Combinators and commas in selector lists are flags in one of the slots so, as you mention, this takes up two slots:
Parameters to functional pseudo classes are currently stored in separate arrays, so selectors like:
still only take up a single slot for the :host pseudo class.
The limitation here is not how many selectors we store for the style rule. You can write a style rule containing more than 2^13 simple selectors and still have the CSSOM serialization show correctly. The limitation is in the meta data for looking up selectors in selector lists during matching, starting at the correct slot for a given selector. We store selectors in buckets based on tag, id, class to be able to skip matching most selectors. If style rules contains more than a single complex selector, we may store each complex selector in different buckets. For instance for:
We only try to match the first selector against elements with id=“id” and only try to match the second against elements with a class attribute containing “class”.
There is a peculiarity for some cases where we add implicit type selectors when there is a default namespace for the sheet for easy of matching, which will affect the number of selectors we store. For this sheet we store an implicit type selector before [attr] to only match elements in the default-ns namespace:
as that is essentially the same as: