question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`restructureRules` can hit the limit of max number of selectors per rule

See original GitHub issue

I’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:closed
  • Created 7 years ago
  • Comments:32 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
jakubpawlowiczcommented, Mar 22, 2017

So it’s fixed on master ^ - I’ll backport it to 4.0 with the fixed limit.

0reactions
ghostcommented, Apr 3, 2017

This selector contains 9 simple selectors and takes up 9 slots in the selector structure:

#checkbox:checked ~ #id[data-foo] input[value=xxx] ~ #foo label:after

Combinators and commas in selector lists are flags in one of the slots so, as you mention, this takes up two slots:

.class, #id

Parameters to functional pseudo classes are currently stored in separate arrays, so selectors like:

:host(#id, .class)

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:

[align] #id, div .class {}

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:

@namespace url(http://default-ns)
[attr] {}

as that is essentially the same as:

@namespace myNs url(http://default-ns)
myNs|*[attr] {}
Read more comments on GitHub >

github_iconTop Results From Across the Web

`restructureRules` can hit the limit of max number of selectors ...
I'm using clean-css 4.0.9 through the command-line (cleancss -O2 'all:off;restructureRules:on' test.css -o test.min.css).
Read more >
The Limits Of CSS Selectors - the new code
Any version of Internet Explorer before version 10 has a limit of 4096 selectors per stylesheet, and will ignore any declarations after ...
Read more >
How long can a CSS selector be? - Stack Overflow
4098 is the limit of total number of selector parts. ... Moreover, the max selectors per style sheet is limited to 4095 css...
Read more >
selector-max-type - Stylelint
This rule resolves nested selectors before counting the number of type selectors. Each selector in a selector list is evaluated separately.
Read more >
Selectors Level 4 - W3C
Selectors are patterns that match against elements in a tree, and as such form one of several technologies that can be used to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found