stylelint-selector-bem-pattern是唯一靠谱方案,因其将BEM解析为block/element/modifier结构树校验,而非仅字符串正则匹配;原生selector-class-pattern无法识别语义层级,易漏检.card__header__icon或误放.btn-primary。

为什么 stylelint-selector-bem-pattern 是唯一靠谱方案?
直接用 Stylelint 原生规则(比如 selector-class-pattern)写 BEM 正则,基本会掉进“匹配太松放行错误”或“匹配太紧误杀合法写法”的坑里。BEM 的嵌套层级、修饰符位置、元素分隔符组合太多,纯正则难以覆盖 __、--、_ 的语义约束。而 stylelint-selector-bem-pattern 是专为 BEM 设计的插件,它把命名解析成结构树(block / element / modifier),再按规则校验,比正则可靠得多。
如何配置支持嵌套与修饰符的完整 BEM 规则?
别只抄官网默认配置——它默认不校验嵌套选择器里的子类名,也不区分修饰符是否只能作用于 block 或 element。实际项目中必须显式开启 componentName 和 styleSheet 模式,并补全 allowedPatterns:
{
"plugins": ["stylelint-selector-bem-pattern"],
"rules": {
"plugin/selector-bem-pattern": {
"preset": "bem",
"componentName": "[a-z]+(?:-[a-z]+)*",
"componentSelectors": {
"initial": "^\.{componentName}(?:__{elementName})?(?:--{modifierName})?$",
"combined": [
"^\.{componentName}__{elementName}(?:--{modifierName})?$",
"^\.{componentName}--{modifierName}$"
]
}
}
}
}-
componentName限制只允许小写字母+短横线,排除.Header2这类数字结尾 -
initial允许顶层.menu--active和.menu__item--disabled,但禁止.menu__item--active这种“元素带独立修饰符”(除非你业务真需要) - 如果允许修饰符链(如
.btn--primary--large),得手动在combined里加正则,原 preset 不含该逻辑
为什么 @nest 和 CSS-in-JS 里的类名常被漏检?
stylelint-selector-bem-pattern 默认只检查普通 CSS 选择器,对 @nest .parent &__child 或 styled-components 中的 css`&__item{}` 完全无感。这类写法需额外启用 postcss-nesting 解析器,并在配置中声明 processors:
{
"processors": ["stylelint-postcss-nesting"],
"rules": {
"plugin/selector-bem-pattern": { /* 同上 */ }
}
}- 没配
processors时,@nest块会被当普通字符串跳过,规则形同虚设 - styled-components / Emotion 的模板字符串需配合
stylelint-processor-styled-components,且必须确保其版本 ≥ 1.10.0(旧版不透传嵌套节点) - Vue 单文件组件中的
<style scoped>无需额外处理器,但需确认postcss插件链已加载postcss-nesting
如何让 CI 拦截失败但本地开发不卡住?
直接设 "plugin/selector-bem-pattern": "error" 会让 PR 因一个命名问题直接挂 CI,但开发者又难记住所有边界 case。更务实的做法是分层控制:
立即学习“前端免费学习笔记(深入)”;
- 本地
stylelint --fix仅警告(warning),配合 VS Code 的stylelint-plus插件实时提示 - CI 环境通过环境变量切换:运行时加
STYLELINT_FAIL_ON_ERROR=1,脚本里读取并动态改规则级别 - 对历史代码用
stylelint --quiet跳过 node_modules 和 legacy 目录,避免一次性修复压力过大
BEM 校验真正的复杂点不在配置,而在团队对 “什么算合法修饰符” 的共识——比如 .card--fluid 和 .card__header--fluid 是否都允许?这得靠 componentSelectors.combined 里明确定义,而不是指望工具自动推断。


















