Skip to content

Instantly share code, notes, and snippets.

@mindplay-dk
Last active March 25, 2024 12:38
Show Gist options
  • Save mindplay-dk/81738eefc675309d63686a7d97da00a6 to your computer and use it in GitHub Desktop.
Save mindplay-dk/81738eefc675309d63686a7d97da00a6 to your computer and use it in GitHub Desktop.
Capture CSS rules being used on the page
/**
* This script captures all CSS rules that are in use on the current page.
*
* - Paste the script into the browser console.
* - Run `collector.rules` to get a list of CSS rules in use.
* - As a diagnostic, run `collector.rulesWithComments` to get a list of CSS rules with comments.
*/
var collector = (() => {
const rulesInUse = new Set();
function* listRules(styleSheets = document.styleSheets) {
for (const s of styleSheets) {
yield { comment: `/* --- ${s.href} --- */` };
try {
for (const rule of s.rules) {
yield { rule };
}
} catch (e) {
console.warn(`WARNING: inaccessible stylesheet`, s);
yield { comment: `/* WARNING: inaccessible stylesheet ${s.href} */` };
}
}
}
function isRuleInUse(rule) {
if (rule.type === CSSRule.STYLE_RULE) {
return !! document.querySelector(rule.selectorText);
}
if (rule.type === CSSRule.MEDIA_RULE) {
return Array.from(rule.cssRules).some(isRuleInUse);
}
if (rule.type === CSSRule.IMPORT_RULE) {
console.warn(rule);
return false;
}
return false;
}
function exportRules(withComments) {
return [...listRules()]
.map(({ rule, comment }) => {
if (comment) {
return withComments ? comment : null;
}
if (rulesInUse.has(rule.cssText)) {
return rule.cssText;
}
return withComments ? `/* ${rule.cssText} */` : null;
})
.filter(Boolean) // remove nulls
.filter((rule, index, self) => self.indexOf(rule) === index) // remove duplicates
.join("\n");
}
function captureRulesInUse() {
const count = rulesInUse.size;
for (const { rule, comment} of listRules()) {
if (comment) {
continue;
}
if (isRuleInUse(rule)) {
rulesInUse.add(rule.cssText);
}
}
if (rulesInUse.size !== count) {
console.log(`Detected ${rulesInUse.size} rules in use`);
}
}
["load", "resize", "scroll", "click", "input", "mouseup", "mousedown", "mousemove"].forEach(event => {
window.addEventListener(event, captureRulesInUse);
});
captureRulesInUse();
return {
get rules() {
return exportRules(false);
},
get rulesWithComments() {
return exportRules(true);
}
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment