BEM本身不剔除未用样式,需靠PurgeCSS等工具识别实际使用的修饰符类名并删除冗余CSS规则;postcss-bem仅编译命名,不分析使用情况。

直接结论:BEM 本身不产生未使用样式,真正要剔除的是修饰符类名对应的实际 CSS 规则——这必须靠 PurgeCSS 类工具完成,不能靠 BEM 命名规范自动解决。
为什么 BEM 修饰符(button--primary)容易残留无用 CSS
BEM 的 -- 修饰符本意是语义化变体,但实践中常被当作“样式开关”滥用:每个尺寸、颜色、状态都拆成独立类名,导致 CSS 文件里塞满碎片规则。这些规则只要没在 HTML/JSX 中真实出现过,就是冗余的。
常见错误现象:button--size-large 在组件中只用于旧版弹窗,新逻辑已改用 button--fluid,但对应 CSS 仍保留在构建产物中;或设计系统升级后,card--shadow-heavy 被弃用,却无人清理。
- 使用场景:组件库迭代、主题切换功能上线后废弃旧修饰符、A/B 测试结束回收实验类名
- 性能影响:Spotify 实测显示,未清理的修饰符类名可使 CSS 体积额外增加 12%~18%,且因选择器碎片化,tree-shaking 几乎无效
- 容易踩的坑:仅靠 PostCSS-BEM 插件校验命名合规性,不等于能识别哪些修饰符真被用了——它不扫描 JS 或模板文件
PurgeCSS 是唯一靠谱的落地方案
必须让工具知道哪些修饰符类名实际出现在运行时 DOM 中。PurgeCSS 不关心你是不是 BEM,它只认字符串匹配:只要 button--primary 出现在 JSX 的 className 或 HTML 的 class 属性里,对应 CSS 就保留;否则删除。
立即学习“前端免费学习笔记(深入)”;
- 配置关键点:路径必须覆盖所有动态生成类名的地方,例如 React 项目要包含
src/**/*.tsx和public/index.html - 白名单必须加:第三方库的修饰符(如
react-datepicker__day--selected)需显式写进whitelistPatterns,否则会被误删 - 动态类名要兜底:像
clsx(`${block}--${size}`)这种拼接,得用whitelistPatterns: [/--(small|medium|large)/]告诉 PurgeCSS 别动这些 - 参数差异:
keyframes和fontFace默认不处理,若修饰符触发了动画(如toast--animate-in),需手动开启keyframes: true
别指望 postcss-bem 自动删修饰符 CSS
postcss-bem 只做一件事:把嵌套写法 .button { &--primary { } } 编译成扁平类名 .button--primary。它不分析使用痕迹,也不读取 JS 文件,更不会删任何一行 CSS。
- 容易踩的坑:误以为开了
postcss-bem就等于“自动优化”,结果构建产物里堆着 57 个未使用的input--variant-*规则 - 正确做法:
postcss-bem仅用于开发阶段保障命名一致性;PurgeCSS 才是上线前的清道夫 - 兼容性注意:若项目仍需支持 IE11,避免在 PurgeCSS 配置中启用
rejected: true(它会用[class^="button--"]这类属性选择器,IE 不认)
真正难的不是配置 PurgeCSS,而是确保所有修饰符类名都以可静态分析的方式出现——比如禁止在 useEffect 里用字符串拼接生成类名,或通过 API 动态注入 class 字符串。这类行为会让 PurgeCSS 彻底失效,只能靠人工维护白名单,而白名单一长,就失去了自动化意义。


















