Unused CSS detector

There is no tool to detect unused CSS blocks. You can find them on a single page, but with all the complication of SPA, there is nothing for that. Or at last, I had not found one. As the app grows older, and the code (and developers) are changing, the amount of unused CSS becomes a problem. It becomes even harder if your CSS is kept poorly, or you are using unskiled LESS and so.

After a huge amount of frustration about the issue, I decided to try making a small JQUERY tool that you can throw into the console and will give you some understanding about your CSS status. Something simple that will query the DOM for unused CSS selectors and will be able to direct you towards the unused section, or provide some approximation about your CSS usage.

This version has only five methods: init, check, start, stop and print. All the data is in the “data” object: used, unused, invalid & cycle number.

First thing you need to do is to get a list of the CSS classes. The most simple way is to download your min CSS file. Then, after some REGUS replacements, you have a list of all the CSS selectors in the site. I wrote the replacements line by like to keep it simple:

1. '}' => '\n'
2. ',' => '\n'
3. '{(.*)}' => ''
4. '\n' => ',\n'
5. Correct first & last lines.

With the list of all the CSS selectors, copy the code into the console:

let cssDetector = {
data : {},
init : (selectors) => {
cssDetector.data = {
cycle: 0,
used : {},
unused : [],
invalid : []}
;
selectors.forEach(selector => {
try{
$(selector);
cssDetector.data.unused.push(selector);
}catch{
cssDetector.data.invalid.push(selector);
}
});

console.log('Invalid: ' + cssDetector.data.invalid.length);
},

check: () => {
let tempUnused = [];
cssDetector.data.unused.forEach(cssSelector => {
if($(cssSelector).length){
if(!cssDetector.data.used[cssSelector]){
cssDetector.data.used[cssSelector] = 0;
}
cssDetector.data.used[cssSelector] += $(cssSelector).length;
}else{
tempUnused.push(cssSelector);
}
});
cssDetector.data.unused = tempUnused;
cssDetector.print();
},

start: () => {
console.log('cssDetector start');
cssDetector.data.timeinterval = setInterval(cssDetector.check,3000);
},

stop: ()=>{
clearInterval(cssDetector.data.timeinterval);
console.log('cssDetector stop');
},

print: () => {
console.log('Cycle : ' + ++cssDetector.data.cycle);
console.log(' Userd : ' + Object.getOwnPropertyNames(cssDetector.data.used).length);
console.log(' Unused: ' + cssDetector.data.unused.length);
if(cssDetector.data.unused.length == 0){
cssDetector.stop();
}
}
}

Init the code with the CSS selectors list:

cssDetector.init(['.classA', '.classB', ...])

You will see log with the number of lines that are not valid CSS selectors:

Invalid: 13

You can view them at:

cssDetector.data.invalid
// ["@ media", "@moz-a", ...]

To check the current static state of the app:

cssDetector.check()
// Cycle : 1
// Userd : 41
// Unused: 132

But since we have a SPA, we will need to move through the app. That way there are a “start” & “stop” methods.

 cssDetector.start()
// Cycle : 2
// Userd : 41
// Unused: 132

// Cycle : 3
// Userd : 35
// Unused: 127

// Cycle: 4
// ...
..

cssDetector.stop()

In the end, you can look at the unused CSS selectors to find out the section you did not visit:

cssDetector.data.unused
// [".moshe",".moshe is",".moshe is #not","here"...

Just restart the cssDetector and go to that section:

cssDetector.start()

The version I’m using is larger and can download the data, detect duplications, merge and so on. But the core concept is the same.

Though this tool is far from giving a complete or accurate solution for the problem, it provides a fast overview and points out the unused section and most of all, much better than all the tools I did not find 😐