<p>必须用@projectwallace/postcss-bem-linter,因原版已归档且不支持嵌套解析、SCSS变量内联及作用域推断;校验依赖顶部注释/ postcss-bem-linter: define .block /,否则.class__elem被视为非法,且需配置ignore正则跳过js-/is-/has-/u-类。</p>

PostCSS 能校验 BEM,不是因为它“懂语义”,而是它在 CSS 编译链路中拿到了原始源码字符串,并能基于显式声明(如 /* postcss-bem-linter: define .block */)做上下文感知的静态分析——没这句声明,.header__logo 就只是个带双下划线的普通类名,插件根本不会把它当作 element。
为什么必须用 @projectwallace/postcss-bem-linter 这个 fork?
原版 postcss-bem-linter 已归档,不处理 SCSS 编译后的嵌套结果,也解析不了 .block__elem--mod 中的修饰符层级。而 @projectwallace/postcss-bem-linter 修复了三点关键问题:
- 支持
&__title这类 SCSS 嵌套语法编译后的产物识别 - 能内联解析
$block-name变量后生成的类名(如.#{$prefix}__icon→.card__icon) - 正确推断作用域:同一文件里多个
define注释可共存,且互不干扰
装错包(比如只执行 npm install postcss-bem-linter)会导致所有校验静默失效,连 .header__logo__icon 这种明显错误都不会报。
校验前不加顶部 define 注释就等于没开开关
postcss-bem-linter 不猜 block 名——它不看文件名、不解析父选择器、也不从类名前缀反推。它只认这一行:
立即学习“前端免费学习笔记(深入)”;
/* postcss-bem-linter: define .header */
这行注释必须出现在 CSS 文件最顶部(或至少在首个 BEM 类之前),否则:
-
.header__logo会被判为 “element not under block” -
.card__body--expanded里的--expanded因无归属 block 被当非法 modifier - 即使你用 SCSS 的
&__title,编译后是.list__title,插件仍要求顶部写define .list
ignore 配置漏掉就全是误报
默认模式下,.js-toggle、.is-open、.u-hidden 全被当成违反 BEM 规则。必须在 postcss.config.js 里明确跳过:
{ preset: 'bem', ignore: [/^js-/, /^is-/, /^has-/, /^u-/] }注意两点:
- 正则必须带
^,否则.button-is-active也会被误放过 - 项目若混用 utility 类(如
.u-text-center)、JS 钩子类(.js-modal-trigger)、状态类(.is-dragging),全得列进ignore
Vite/Webpack 里插件根本没跑?先查 PostCSS 是否介入
校验失败最常见的原因是 CSS 根本没走 PostCSS 流程:
- Vite 默认对
.css文件用 esbuild 处理,绕过 PostCSS;需在vite.config.ts中确认css.postcss.plugins数组包含@projectwallace/postcss-bem-linter - Webpack 必须确保
postcss-loader在css-loader之前,且postcss.config.js路径正确 - 插件顺序很重要:
postcss-bem-linter必须在cssnano之前,否则压缩后类名变形(如.header__logo→.a__b),校验直接失效
验证是否生效最简单的方法:在 CSS 里故意写个错命名(如 .header__logo__icon),运行构建——不报错,说明链路断了。
真正难的不是配对参数,而是让每个 define .xxx 注释严格对应组件边界:一个文件只声明一个 block,动态拼接的类名(class="header__${state}")必须进 ignore,而 utility 类和 JS 钩子类一旦漏配,就会淹没真实问题。


















