Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Count the number of rules and selectors for CSS files on the page. Flags up the >4096 threshold that confuses IE
function countCSSRules() {
var results = '',
log = '';
if (!document.styleSheets) {
return;
}
for (var i = 0; i < document.styleSheets.length; i++) {
countSheet(document.styleSheets[i]);
}
function countSheet(sheet) {
var count = 0;
if (sheet && sheet.cssRules) {
for (var j = 0, l = sheet.cssRules.length; j < l; j++) {
if( !sheet.cssRules[j].selectorText ) {
continue;
}
count += sheet.cssRules[j].selectorText.split(',').length;
}
log += '\nFile: ' + (sheet.href ? sheet.href : 'inline <style> tag');
log += '\nRules: ' + sheet.cssRules.length;
log += '\nSelectors: ' + count;
log += '\n--------------------------';
if (count >= 4096) {
results += '\n********************************\nWARNING:\n There are ' + count + ' CSS rules in the stylesheet ' + sheet.href + ' - IE will ignore the last ' + (count - 4096) + ' rules!\n';
}
}
}
console.log(log);
console.log(results);
};
countCSSRules();
@fastmover

This comment has been minimized.

Show comment Hide comment
@fastmover

fastmover Oct 23, 2012

I'm getting TypeError: Cannot call method 'split' of undefined

I'm getting TypeError: Cannot call method 'split' of undefined

@slav

This comment has been minimized.

Show comment Hide comment
@slav

slav Nov 12, 2012

so just add if( !sheet.cssRules[j].selectorText ) continue; to the for loop

slav commented Nov 12, 2012

so just add if( !sheet.cssRules[j].selectorText ) continue; to the for loop

@psebborn

This comment has been minimized.

Show comment Hide comment
@psebborn

psebborn Jul 12, 2013

@slav - Nice idea, thanks - I've updated the gist now to include that :)

Owner

psebborn commented Jul 12, 2013

@slav - Nice idea, thanks - I've updated the gist now to include that :)

@dheniges

This comment has been minimized.

Show comment Hide comment
@dheniges

dheniges Oct 29, 2013

This is awesome, thanks

This is awesome, thanks

@jwarchol

This comment has been minimized.

Show comment Hide comment
@jwarchol

jwarchol Nov 13, 2013

This won't work if your stylesheets are hosted on another domain due to cross domain permissions voodoo. Just leaving this as a note to anyone using a CDN or something who is confused, as I was, about why it wasn't working.

This won't work if your stylesheets are hosted on another domain due to cross domain permissions voodoo. Just leaving this as a note to anyone using a CDN or something who is confused, as I was, about why it wasn't working.

@sattes-faction

This comment has been minimized.

Show comment Hide comment
@sattes-faction

sattes-faction Nov 28, 2013

Awesome, saved me a lot of time, thanks!

Awesome, saved me a lot of time, thanks!

@stowball

This comment has been minimized.

Show comment Hide comment
@stowball

stowball Jan 29, 2014

Firefox/Firebug errors with:

Error: The operation is insecure.
if (sheet && sheet.cssRules) {

Firefox/Firebug errors with:

Error: The operation is insecure.
if (sheet && sheet.cssRules) {

@colinbashbash

This comment has been minimized.

Show comment Hide comment
@colinbashbash

colinbashbash Feb 6, 2014

very awesome. i just paste the whole thing in the console window in firebug and it prints it all out

UPDATED
You can avoid the "operation is insecure* error by adding the following code before "if (sheet && sheet.cssRules)

if (sheet.href != null && sheet.href.indexOf(location.origin) != 0){
     console.log("CSS file couldn't be analyzed because it is not on the same domain: " + sheet.href);
     return;
}

very awesome. i just paste the whole thing in the console window in firebug and it prints it all out

UPDATED
You can avoid the "operation is insecure* error by adding the following code before "if (sheet && sheet.cssRules)

if (sheet.href != null && sheet.href.indexOf(location.origin) != 0){
     console.log("CSS file couldn't be analyzed because it is not on the same domain: " + sheet.href);
     return;
}
@AaronV

This comment has been minimized.

Show comment Hide comment
@AaronV

AaronV Jun 12, 2014

If you add an if statement to count the number of sheets, you can have this also catch IEs bug where it won't load more than 30 stylesheets at a time:

if (document.styleSheets.length >= 30) {
    results += 'Found ' + document.styleSheets.length + ' stylesheets. <= IE9 will ignore stylesheets after 30!\n';
}

AaronV commented Jun 12, 2014

If you add an if statement to count the number of sheets, you can have this also catch IEs bug where it won't load more than 30 stylesheets at a time:

if (document.styleSheets.length >= 30) {
    results += 'Found ' + document.styleSheets.length + ' stylesheets. <= IE9 will ignore stylesheets after 30!\n';
}
@stuff

This comment has been minimized.

Show comment Hide comment
@stuff

stuff Jul 25, 2014

just a word to say it's not so reliable. Got the bug and the script indicate <3800 rules :(

stuff commented Jul 25, 2014

just a word to say it's not so reliable. Got the bug and the script indicate <3800 rules :(

@maephisto666

This comment has been minimized.

Show comment Hide comment
@maephisto666

maephisto666 Jul 31, 2014

IMHO u should change the print line at the end (count is for selectors, not for rules).

if (count >= 4096) {
results += '\n********************************\nWARNING:\n There are ' + count + ' CSS selectors in the stylesheet ' + sheet.href + ' - IE will ignore the last ' + (count - 4096) + ' selectors!\n';
}

IMHO u should change the print line at the end (count is for selectors, not for rules).

if (count >= 4096) {
results += '\n********************************\nWARNING:\n There are ' + count + ' CSS selectors in the stylesheet ' + sheet.href + ' - IE will ignore the last ' + (count - 4096) + ' selectors!\n';
}
@webberig

This comment has been minimized.

Show comment Hide comment
@webberig

webberig Aug 14, 2014

Same problem here... I got less then 3500 and it still isn't working.

Same problem here... I got less then 3500 and it still isn't working.

@labue

This comment has been minimized.

Show comment Hide comment
@labue

labue Aug 26, 2014

Cool snippet, however it does not seem to count the CSSMediaRule objects, only the first level CSSStyleRule. CSSMediaRule can have multiple CSSStyleRule objects within.

I added this:

for (var j = 0, l = sheet.cssRules.length; j < l; j++) {
    if (!sheet.cssRules[j].selectorText) {
        if (sheet.cssRules[j].cssRules) {
            for (var m = 0, n = sheet.cssRules[j].cssRules.length; m < n; m++) {
                count += sheet.cssRules[j].cssRules[m].selectorText.split(',').length;
            }
        }
    }
    else {
        count += sheet.cssRules[j].selectorText.split(',').length;
    }
}

And went from Rules: 2350, Selectors: 2654 to Rules: 2350, Selectors: 4318.

labue commented Aug 26, 2014

Cool snippet, however it does not seem to count the CSSMediaRule objects, only the first level CSSStyleRule. CSSMediaRule can have multiple CSSStyleRule objects within.

I added this:

for (var j = 0, l = sheet.cssRules.length; j < l; j++) {
    if (!sheet.cssRules[j].selectorText) {
        if (sheet.cssRules[j].cssRules) {
            for (var m = 0, n = sheet.cssRules[j].cssRules.length; m < n; m++) {
                count += sheet.cssRules[j].cssRules[m].selectorText.split(',').length;
            }
        }
    }
    else {
        count += sheet.cssRules[j].selectorText.split(',').length;
    }
}

And went from Rules: 2350, Selectors: 2654 to Rules: 2350, Selectors: 4318.

@krisbulman

This comment has been minimized.

Show comment Hide comment
@krisbulman

krisbulman Sep 3, 2014

Thanks @labue! I forked the snippet with your changes https://gist.github.com/krisbulman/0f5e27bba375b151515d

Thanks @labue! I forked the snippet with your changes https://gist.github.com/krisbulman/0f5e27bba375b151515d

@chibicode

This comment has been minimized.

Show comment Hide comment
@chibicode

chibicode Nov 18, 2014

For anyone looking for a Grunt script: (see maxSelectors)
https://github.com/phamann/grunt-css-metrics

For anyone looking for a Grunt script: (see maxSelectors)
https://github.com/phamann/grunt-css-metrics

@welsh-dwarf

This comment has been minimized.

Show comment Hide comment
@welsh-dwarf

welsh-dwarf Jan 14, 2015

Here's a version that takes @include statements into account:

https://gist.github.com/welsh-dwarf/806aa82ccf7fe529dd56

Here's a version that takes @include statements into account:

https://gist.github.com/welsh-dwarf/806aa82ccf7fe529dd56

@justinmarsan

This comment has been minimized.

Show comment Hide comment
@justinmarsan

justinmarsan Jan 30, 2015

Just a side-note for people saying it's not reliable because their stylesheet has less than 4096 rules and still breaks in IE9 : the number of selectors isn't the only limit regarding CSS files in IE9-.

  • Number of @import's (31)
  • Nesting @import's (4 levels)
  • File size (278Kb|288Kb)

So yes you may have less than 4096 selectors and still have your stylesheet break in IE9, check for datauri images, auto-generated selectors (compass sprites and @extend for example) and if possible move styles used after load in another stylesheet loaded before the closing body tag (modal popups, jQueryUI stylings, that sort of things) so the broser renders elements that are there right away and loads the rest before it happens on the page if it comes from user interaction.

Thanks for the gist, helped me figure out my problem wasn't a selector limit issue, but removing some datauri images did the trick for me.

Just a side-note for people saying it's not reliable because their stylesheet has less than 4096 rules and still breaks in IE9 : the number of selectors isn't the only limit regarding CSS files in IE9-.

  • Number of @import's (31)
  • Nesting @import's (4 levels)
  • File size (278Kb|288Kb)

So yes you may have less than 4096 selectors and still have your stylesheet break in IE9, check for datauri images, auto-generated selectors (compass sprites and @extend for example) and if possible move styles used after load in another stylesheet loaded before the closing body tag (modal popups, jQueryUI stylings, that sort of things) so the broser renders elements that are there right away and loads the rest before it happens on the page if it comes from user interaction.

Thanks for the gist, helped me figure out my problem wasn't a selector limit issue, but removing some datauri images did the trick for me.

@mminguezz

This comment has been minimized.

Show comment Hide comment
@mminguezz

mminguezz Feb 26, 2015

in my ie8, the rule 4096 does not apply.
as said justinmarsan "stylesheet has less than 4096 rules"

in my ie8, the rule 4096 does not apply.
as said justinmarsan "stylesheet has less than 4096 rules"

@danieljin

This comment has been minimized.

Show comment Hide comment
@danieljin

danieljin Mar 27, 2015

Using @krisbulman's function gave me the actual results i was looking for.

Using @krisbulman's function gave me the actual results i was looking for.

@wesbot

This comment has been minimized.

Show comment Hide comment
@wesbot

wesbot Jun 12, 2015

Brilliant job, thanks!

wesbot commented Jun 12, 2015

Brilliant job, thanks!

@screeny05

This comment has been minimized.

Show comment Hide comment
@screeny05

screeny05 Feb 4, 2016

Saw this and just had to remake it with es6.

This snippet counts selectors recursively, so it also finds selectors inside media-queries. Also it requires a modern browser.

(function(){
  var countSelectorsInStylesheet = container => Array.from(container.cssRules).reduce((prev, cur) => {
    prev = rule.selectorText ? prev + rule.selectorText.split(',').length : prev;
    prev = rule.cssRules ? prev + countSelectorsInStylesheet(rule) : prev; 
  });
  Array.from(document.styleSheets).forEach(sheet => console.log(sheet.href, countRules(sheet), 'selectors'));
})();

have fun!

Saw this and just had to remake it with es6.

This snippet counts selectors recursively, so it also finds selectors inside media-queries. Also it requires a modern browser.

(function(){
  var countSelectorsInStylesheet = container => Array.from(container.cssRules).reduce((prev, cur) => {
    prev = rule.selectorText ? prev + rule.selectorText.split(',').length : prev;
    prev = rule.cssRules ? prev + countSelectorsInStylesheet(rule) : prev; 
  });
  Array.from(document.styleSheets).forEach(sheet => console.log(sheet.href, countRules(sheet), 'selectors'));
})();

have fun!

@dfbfloyd

This comment has been minimized.

Show comment Hide comment
@dfbfloyd

dfbfloyd Jul 22, 2016

This is great! Saved me a ton of time. As colinbashbash said, I opened Firebug, pasted the code into the console window and clicked run. It took me 30 seconds at the most.

This is great! Saved me a ton of time. As colinbashbash said, I opened Firebug, pasted the code into the console window and clicked run. It took me 30 seconds at the most.

@ka2n

This comment has been minimized.

Show comment Hide comment
@ka2n

ka2n Dec 20, 2016

A modified version of @screeny05's snippet, works well on Google Chrome's console.

(function(){
  var countSelectorsInStylesheet = container => Array.from(container.cssRules).reduce((prev, rule) => {
    prev = rule.selectorText ? prev + rule.selectorText.split(',').length : prev;
    prev = rule.cssRules ? prev + countSelectorsInStylesheet(rule) : prev
    return prev
  }, 0);
  Array.from(document.styleSheets).forEach(sheet => console.log(sheet.href ? sheet.href : "inline", countSelectorsInStylesheet(sheet), 'selectors'));
})();

ka2n commented Dec 20, 2016

A modified version of @screeny05's snippet, works well on Google Chrome's console.

(function(){
  var countSelectorsInStylesheet = container => Array.from(container.cssRules).reduce((prev, rule) => {
    prev = rule.selectorText ? prev + rule.selectorText.split(',').length : prev;
    prev = rule.cssRules ? prev + countSelectorsInStylesheet(rule) : prev
    return prev
  }, 0);
  Array.from(document.styleSheets).forEach(sheet => console.log(sheet.href ? sheet.href : "inline", countSelectorsInStylesheet(sheet), 'selectors'));
})();
@ElijahLynn

This comment has been minimized.

Show comment Hide comment
@ElijahLynn

ElijahLynn Oct 6, 2017

This thread is nice and helpful! I got errors on @ka2n and @screeny05 on Chrome 59. @welsh-dwarf works out-of-the-box!

https://gist.github.com/welsh-dwarf/806aa82ccf7fe529dd56

This thread is nice and helpful! I got errors on @ka2n and @screeny05 on Chrome 59. @welsh-dwarf works out-of-the-box!

https://gist.github.com/welsh-dwarf/806aa82ccf7fe529dd56

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment