Skip to content

Instantly share code, notes, and snippets.

@kdzwinel

kdzwinel/main.js

Last active Jun 4, 2021
Embed
What would you like to do?
List all undefined CSS classes
/*
This script attempts to identify all CSS classes mentioned in HTML but not defined in the stylesheets.
In order to use it, just run it in the DevTools console (or add it to DevTools Snippets and run it from there).
Note that this script requires browser to support `fetch` and some ES6 features (fat arrow, Promises, Array.from, Set). You can transpile it to ES5 here: https://babeljs.io/repl/ .
Known limitations:
- it won't be able to take into account some external stylesheets (if CORS isn't set up)
- it will produce false negatives for classes that are mentioned in the comments.
*/
(function () {
"use strict";
//get all unique CSS classes defined in the main document
let allClasses = Array.from(document.querySelectorAll('*'))
.map(n => Array.from(n.classList))
.reduce((all, a) => all ? all.concat(a) : a)
.reduce((all, i) => all.add(i), new Set());
//load contents of all CSS stylesheets applied to the document
let loadStyleSheets = Array.from(document.styleSheets)
.map(s => {
if (s.href) {
return fetch(s.href)
.then(r => r.text())
.catch(e => {
console.warn('Coudn\'t load ' + s.href + ' - skipping');
return "";
});
}
return s.ownerNode.innerText
});
Promise.all(loadStyleSheets).then(s => {
let text = s.reduce((all, s) => all + s);
//get a list of all CSS classes that are not mentioned in the stylesheets
let undefinedClasses = Array.from(allClasses)
.filter(c => {
var rgx = new RegExp(escapeRegExp('.' + c) + '[^_a-zA-Z0-9-]');
return !rgx.test(text);
});
if(undefinedClasses.length) {
console.log('List of ' + undefinedClasses.length + ' undefined CSS classes: ', undefinedClasses);
} else {
console.log('All CSS classes are defined!');
}
});
function escapeRegExp(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
})();
@kdzwinel

This comment has been minimized.

Copy link
Owner Author

@kdzwinel kdzwinel commented Oct 8, 2015

Sample output:

undefinedcssclasses

@kdzwinel

This comment has been minimized.

Copy link
Owner Author

@kdzwinel kdzwinel commented Oct 8, 2015

x-skeww pointed out that:

Doesn't work with funky (albeit totally legit) classes à la "1/2"

and provided a fix:

c = CSS.escape(c);
var rgx = new RegExp(escapeRegExp('.' + c) + '\\b');

Unfortunately, CSS.escape is not yet available in the, currently stable, Chrome 45 (it will be in the next version though). I'll update the snippet as soon as Chrome 46 goes stable.

@simlevesque

This comment has been minimized.

Copy link

@simlevesque simlevesque commented Oct 8, 2015

All this needs is a bot that goes through all the routes on your website to test it's unused classes and keeps a list of only the classes that are not used in any page of the website.

@johnnywalters

This comment has been minimized.

Copy link

@johnnywalters johnnywalters commented Oct 8, 2015

We use classes a lot so our JS has something to target. So I'll get back 50 results but I don't know if they are in some JS file somewhere or if they are safe to weed out.

@stefanfisk

This comment has been minimized.

Copy link

@stefanfisk stefanfisk commented Oct 8, 2015

@johnnywalters a long term fix for that is to use separate classes for js with a clear naming standard, but of course it's no small change.

@mchandleraz

This comment has been minimized.

Copy link

@mchandleraz mchandleraz commented Oct 8, 2015

@simlevesque this shouldn't even be happening on deployed code. This kinda of stuff should be done during build/deployment, with tools like grunt/gulp/broccoli.

@kdzwinel

This comment has been minimized.

Copy link
Owner Author

@kdzwinel kdzwinel commented Oct 8, 2015

@simlevesque it's the other way around - this script looks for classes used in HTML that are not defined in CSS.

@johnnywalters @stefanfisk yeah, we prefix all JS specific classes with js- for clarity. Here it pays of. Trying to programmatically figure out if some class is used in JS would be very hard.

@mchandleraz it sure can, and I encourage you to take my code and build gulp/grunt/broccoli plugin on the top of it. However, this will only work for static pages. Web apps (that are build by JS in the runtime) and pages constructed with templates (e.g. twig) won't be that easy to search through.

@Eddolan

This comment has been minimized.

Copy link

@Eddolan Eddolan commented Oct 9, 2015

@johnnywalters and @stefanfisk I believe that purify css has the ability to detect classes added by JS.

@broofa

This comment has been minimized.

Copy link

@broofa broofa commented May 15, 2021

Update for 2021 (modern JS and browsers): It's no longer necessary to fetch() the style sheets. Instead, all modern browsers now support document.styleSheets[*].cssRules[*].selectorText, which can be used for reliable detection of defined CSS classes w/out the caveats in the original script. There is also the MutationObserver API, which can be used to dynamically watch for changes to the DOM.

See the https://www.npmjs.com/package/checkcss module that I just published for details.

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