← 返回工具指南
工具指南unused CSS未使用 CSSCSS 清理CSS 选择器前端性能

未使用 CSS 怎么查才不误删:静态匹配、动态类与页面覆盖

清理 unused CSS 不能只看一张静态页面。本文说明选择器匹配、hover 等动态状态、运行时类、路由覆盖与逐批删除流程。

打开配套工具 →

旧项目的 CSS 往往只增不减。换过几轮页面、主题和组件后,样式文件里会留下看似没人使用的 .old-banner.legacy-modal 和很长的后代选择器。把它们全部删掉,文件确实会变小;问题是某个只在登录失败、移动端菜单或节日活动出现的状态,也可能一起消失。

未使用 CSS 选择器检查工具适合先做页面级审计:输入 HTML 与相关 CSS,它会区分已命中、未命中、动态状态和无效选择器,并保留 @media@supports@layer 等上下文。它输出的是候选清单,不会直接生成一份冒险的 clean.css

“未使用”必须先说明范围

对一份静态 HTML 来说,选择器没有匹配元素,可以准确描述为“当前文档未命中”。但这和“整个网站永远不用”不是一回事。

一条规则可能出现在:

因此一次静态检查只能回答“这份样本是否命中”。工具越诚实地说明范围,结果越有用。

hover、focus 和伪元素为什么容易被误判

下面这条规则在页面刚加载时未必成立:

css已剪下 ✓
.button:hover::before {
  opacity: 1;
}

:hover 要等指针进入元素,::before 也不是 DOM 里的普通节点。如果分析器直接执行 querySelectorAll('.button:hover::before'),很可能得到空结果,甚至因为伪元素而报错。

更合理的静态处理是先看基底 .button 是否存在,再把整条规则标为动态确认。:focus:checked:target:valid:open:fullscreen 等状态也应采用相同思路。

基底存在,不代表状态样式一定正确;基底不存在,也不代表其他页面没有。它只是比简单的“0 个元素,所以删除”多了一层必要的判断。

JavaScript 动态类需要保留词

很多组件不会把完整状态写在初始 HTML 里:

js已剪下 ✓
document.documentElement.classList.add("js-ready");
dialog.classList.toggle("is-open", open);

静态样本里看不到 js-readyis-open,对应样式却可能是核心交互。审计前可以从代码搜索、组件文档和运行时 DOM 中整理保留词,例如:

text已剪下 ✓
js-ready
is-open
modal-open
loading

保留词不应靠猜。把 activeopenhidden 等所有常见词一股脑加入,会让报告失去筛选价值。更好的办法是搜索 classList、模板条件、组件状态映射和第三方插件文档,记录真实出现的动态类。

选择器列表要逐项判断

一条 CSS 规则可以包含多个选择器:

css已剪下 ✓
.article-title,
.legacy-title,
.modal-title:hover {
  font-weight: 700;
}

其中第一项可能已使用,第二项未命中,第三项依赖动态状态。把整条规则简单标成“使用”或“未使用”都不够准确。审计结果应把逗号列表拆开,分别记录命中数和判断原因。

真正改代码时,也不能只删掉整个声明块。应该保留使用中的选择器,移除确认无用的成员,并继续保持声明顺序和所在条件不变。

@media、@supports 和 @layer 不能被抹掉

下面的 .sidebar 在窄屏不会生效,但仍可能用于桌面:

css已剪下 ✓
@media (min-width: 1024px) {
  .sidebar { display: block; }
}

静态匹配可以确认 HTML 有没有 .sidebar,却不能只根据当前窗口判断媒体条件是否有价值。@supports@container 也一样。@layer 还会影响级联顺序,移动规则或重新输出 CSS 可能改变最终样式。

因此报告应保留条件上下文。清理时在原文件里修改,而不是把所有“已使用规则”拼成一份丢失结构的新 CSS。

浏览器 Coverage 和静态匹配各自解决什么

Chrome DevTools 的 Coverage 会记录当前实际执行过程中哪些 CSS 字节被使用。它适合走一遍真实交互、不同视口和路由,发现运行时覆盖情况。但没触发到的状态仍会显示未使用,单次操作也无法覆盖所有用户路径。

静态 HTML 匹配可以快速解释每条选择器为何命中或未命中,适合代码审查和小样本。它看不到 JavaScript 后续生成的状态。

两者结合更可靠:静态报告先缩小范围,Coverage 再覆盖真实交互,最后用项目全局搜索确认类名来源。

一套不容易翻车的清理流程

先建立基线:记录生产 CSS 大小、关键页面截图和自动化测试结果。选择一个页面或组件,而不是一次处理整个站点。

把对应 HTML 与 CSS 放进审计工具,给真实动态类配置保留词。先处理语法无效和明显属于已下线模块的选择器,再检查未命中候选。

对每个候选执行三步:

  1. 在整个仓库搜索类名、ID 和模板片段;
  2. 在不同路由、视口和交互状态查看运行时 DOM;
  3. 小批量删除后跑视觉回归、端到端测试和生产构建。

每一批都单独提交。出现问题时可以准确回滚,不需要从一次删除几千行的提交里找原因。

总结

未使用 CSS 不是一个只靠正则或单页扫描就能得出的绝对结论。真正可靠的清理需要明确样本范围,区分动态状态,保留条件上下文,并把静态检查、运行时 Coverage、仓库搜索和回归测试连起来。

把工具当作审计助手,而不是自动删除器。这样 CSS 会逐步变小,页面也不会在某个没人记得的状态里突然失去样式。