PostCSS 本身不生成 BEM 结构,真正起作用的是 postcss-bem(补全嵌套写法)和 @projectwallace/postcss-bem-linter(校验结构);二者均需显式声明上下文(如 scope 或顶部注释),否则静默失效。

PostCSS 本身不生成 BEM 结构,真正起作用的是 postcss-bem(补全嵌套写法)和 @projectwallace/postcss-bem-linter(校验结构)这两类插件;它们都不“自动推断”block,必须显式声明上下文,否则什么都不会做。
postcss-bem 只拼接,不识别语义
postcss-bem 不是命名生成器,它只做纯文本拼接:看到 &__icon 就替换成 .block__icon,但前提是已配置 scope: '.block'。它不解析类名、不读文件名、不看父选择器,只认你写的 scope 配置。
- scope 必须是完整类选择器,比如
'.card',不能写'card'或'.card__header' - 它只处理独立出现的
.__xxx或._xxx(后者需手动配modifier: '_'),对.card .__title这种写法才生效;写成.card { &__title { } }是无效的——它不解析嵌套语法 - 若用了
postcss-nested,postcss-bem必须放在它之后,否则看到的还是未展开的选择器 - 默认分隔符是
{ element: '__', modifier: '--' },改了就得同步调整写法,比如写._active却没配modifier: '_',就完全忽略
postcss-bem-linter 不靠类名猜上下文
@projectwallace/postcss-bem-linter(推荐用这个 fork 版本)不分析类名前缀,它只认 CSS 文件顶部的注释指令:/* postcss-bem-linter: define .block-name */。没这句,所有带 __ 的类都会被当成游离元素报错。
- 即使文件名是
header.css,或父选择器是.header,插件也完全不推断——必须手写注释 - SCSS 编译后生成的
.list__item,PostCSS 层看不到&__item,所以仍需顶部加/* postcss-bem-linter: define .list */ - 动态拼接类名如
class="header__${state}"静态分析无法覆盖,必须加入ignore列表,比如ignore: [/^header__/] - 和
stylelint-selector-bem-pattern混用时,若没配ignore,js-toggle类会被反复报错
Vite/webpack 中插件根本没运行?检查这三处
构建工具默认可能绕过 PostCSS,导致插件形同虚设。最容易漏掉的集成点有三个:
立即学习“前端免费学习笔记(深入)”;
- Vite 对普通
.css文件默认走esbuild,必须在vite.config.ts中显式启用:css.postcss.plugins,或确保postcss.config.js存在且被识别 -
.module.css默认不走 PostCSS,得配css.modules.locals并手动挂载插件链 - 插件顺序错了会失效:比如把
postcss-bem-linter放在postcss-bem之前,它检查的还是未补全的选择器
最常被忽略的不是语法,而是上下文声明——postcss-bem 和 postcss-bem-linter 都不会主动“发现” block,它们只响应你明确写下的 scope 或 /* postcss-bem-linter: define ... */。漏掉任意一个,整个链路就静默失效。


















