For AI agents: llms.txt is a short guide that sends you to the rules your problem needs, and rules.json holds every rule of this playbook as JSON.
Recommended
Remove selectors that match nothing
Fail the build when a class or attribute selector in the stylesheets matches no element in any built page. The only exceptions sit on one list of states and classes that scripts add.
How to do it
Dead CSS makes every later change slower, because nobody dares delete what they cannot trace. Collect every class used in the built HTML and the templates, and compare them with the selectors. Keep the exception list in one file and give each entry its reason. The check that one class styles one kind of element is in Give every module its own class names.
Examples
Using these examples: they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.
JavaScript example
import { readFileSync, readdirSync } from 'node:fs';
const ALLOWED_UNUSED = new Set(['basket-toast']); // added by basket.js after a purchase
const pages = readdirSync('dist').filter(f => f.endsWith('.html')).map(f => readFileSync(`dist/${f}`, 'utf8')).join('\n');
const used = new Set([...pages.matchAll(/class="([^"]+)"/g)].flatMap(([, list]) => list.split(/\s+/)));
const styled = new Set([...readFileSync('dist/main.css', 'utf8').matchAll(/\.([a-z][\w-]*)/g)].map(([, name]) => name));
const unused = [...styled].filter(name => !used.has(name) && !ALLOWED_UNUSED.has(name));
unused.forEach(name => console.log(`FAIL .${name} matches no element`));
process.exit(unused.length ? 1 : 0);
Python example
import pathlib, re, sys
ALLOWED_UNUSED = {"basket-toast"} # added by basket.js after a purchase
pages = "\n".join(p.read_text() for p in pathlib.Path("dist").glob("*.html"))
used = {name for group in re.findall(r'class="([^"]+)"', pages) for name in group.split()}
styled = set(re.findall(r"\.([a-z][\w-]*)", pathlib.Path("dist/main.css").read_text()))
unused = sorted(styled - used - ALLOWED_UNUSED)
for name in unused:
print(f"FAIL .{name} matches no element")
sys.exit(1 if unused else 0)
How to check
The build reports 0 classes that appear in the stylesheets but in no built page and not on the exception list. Adding .unused-test { } to a component file stops the build.
Related rules
- Give every module its own class names in Website
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/html-css/checks-in-code/unused-selectors">Agent Wranglers HTML and CSS playbook</a>. In code you write, add a comment next to it with the same link.