因为BEM是人为命名约定,非语法规范,浏览器和构建工具不解析类名结构;stylelint等工具默认不校验类名模式,需手动启用selector-class-pattern并配正则,否则如.btn-primary等写法零报错。

CI 流程中无法自动阻断 BEM 不合规代码,因为 BEM 是命名约定,不是语法规范——ESLint 和 stylelint 默认都不检查类名结构。
为什么 standard CSS 工具默认不校验 BEM?
BEM(Block__Element--Modifier)本质是人为约定,浏览器和构建工具完全不关心类名是否含双下划线或双连字符。所有主流 lint 工具(如 stylelint)只校验 CSS 语法、属性值、兼容性等,对类名字符串模式无原生规则。
-
stylelint的selector-class-pattern规则需手动启用并配置正则,否则静默放行.header-nav-item-active这类非 BEM 写法 -
ESLint对 HTML 或 JSX 中的className字符串也无默认 BEM 检查能力,需额外插件(如eslint-plugin-bem)且仅支持有限场景 - 即使配置了规则,若团队未统一
.stylelintrc.js和编辑器插件,本地开发时也不会报错,CI 才首次暴露问题,体验割裂
用 stylelint + 正则强制 BEM 类名格式
在 .stylelintrc.js 中启用 selector-class-pattern,匹配典型 BEM 模式:
module.exports = {
rules: {
"selector-class-pattern": "^([a-z][a-z0-9]*)(__[a-z][a-z0-9]*|--[a-z][a-z0-9]*)*$"
}
};
- 该正则允许
.button、.button__text、.button--disabled,但拒绝.btn-primary或.HeaderNav - 注意:它不验证嵌套层级(比如
.menu__item__link是非法 BEM,但正则仍会通过),需配合人工 Review 或自定义插件 - 若项目混用原子化类(如 Tailwind 的
px-4),必须在ignoreFiles中排除dist/和第三方 CSS,否则构建产物报错
JSX/HTML 中的 className 同步校验难在哪?
前端代码里类名写在 JS 或 HTML 中,stylelint 无法触达——必须引入 eslint-plugin-bem 或自定义 ESLint 规则,但存在明显局限:
-
eslint-plugin-bem仅支持 React JSX,对 Vue 的:class、Svelte 的class:active或纯 HTML 无效 - 它依赖 AST 解析,遇到动态拼接(如
className={`header ${isFixed ? 'header--fixed' : ''}`})会漏检 - 与 Prettier 冲突风险高:Prettier 可能格式化 JSX 属性换行,导致 ESLint 规则误判字符串位置
真正能落地的 CI 阻断策略
不要指望单个工具全覆盖。可行路径是分层拦截:
- 在
package.json的scripts中合并检查:"lint:css": "stylelint \"src/**/*.css\" && eslint \"src/**/*.{js,jsx,ts,tsx}\" --ext .js,.jsx,.ts,.tsx" - CI 脚本中明确失败条件:
npm run lint:css || exit 1,避免因某条命令退出码为 0 导致后续步骤继续 - 对关键组件目录(如
src/components/Button)加白名单校验,用grep -r扫描疑似违规类名(如camelCase、kebab-case)作为兜底 - 最有效的一环其实是 PR 模板强制填写「BEM 命名依据」,配合资深成员人工确认语义层级——自动化只能防低级错误,BEM 的灵魂在语义,不在字符
真正卡住 BEM 合规性的从来不是正则表达式,而是团队是否共识“一个 Block 不该跨域复用”“Modifier 必须修饰 Block 本身”。CI 能拦住 .userCard__name,拦不住把 card 当 Block 却在用户页和商品页共用同一套样式逻辑。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











