Modifier必须语义化命名、紧贴Block或Element、独立书写;禁用样式值(如--small)、跨级(如card--featured__image)和连缀(如btn--primary-loading),否则导致样式失效、JS选择器失配及维护困难。

Modifier命名混乱,本质是把“样式结果”当成了“语义意图”,比如写 btn--small 或 card__header--16px,这类类名一改设计就失效,还容易引发JS选择器查不到元素的错误。
Modifier必须用语义词,不能用样式值
修饰符不是CSS属性快照,而是对组件行为或角色的声明。写 btn--primary 是对按钮“主操作角色”的表达;写 btn--small 却只记录了当前尺寸,一旦设计稿把“small”按钮改成高 48px、圆角 12px,类名就自相矛盾。
- ✅ 推荐:
btn--compact(强调空间效率)、btn--icon-only(强调交互形式) - ❌ 避免:
btn--24px、text--14px、bg--#f0f0f0 - 表单控件倾向状态型:
input--valid、input--disabled - 布局组件倾向意图型:
sidebar--pinned、card--featured
Modifier只能紧贴Block或Element,不跨级、不嵌套
Modifier没有“继承性”,它只作用于它直接挂载的那个 Block 或 Element。写 card--featured__image 或 card__header--large--dark 都是无效结构——前者把 Modifier 错误地挂在 Block 上却想影响子 Element,后者试图用两个 -- 连缀,浏览器会当成一个类名,但工具链(如 stylelint)无法识别,VS Code 插件也失焦。
- ✅ 正确:
card__image--rounded(修饰 card__image 元素) - ✅ 正确:
card--featured(修饰 card 块本身) - ❌ 错误:
card--featured__image(跨级,语义断裂) - ❌ 错误:
card__header--large--dark(双 Modifier 连写,违反 BEM 原子性)
多个Modifier共存时,必须独立书写、不可合并
一个按钮同时是主要按钮 + 加载中状态,应该写成 btn btn--primary btn--loading,而不是 btn--primary-loading。后者看似省事,实则带来三个硬伤:无法用 JS 动态增删单一状态、CSS-in-JS 条件拼接失效、Sass 循环生成时失去组合自由度。
立即学习“前端免费学习笔记(深入)”;
- JS 操作更安全:
el.classList.add('btn--loading')不影响btn--primary - 构建工具可 Tree-shake:
btn--loading可被单独抽离或按需加载 - 禁止用 Sass
@each自动生成连缀类,比如.btn--#{$mod}→btn--primary-loading,这等于主动放弃 BEM 的可预测性
Modifier命名要和Block/Element并列,不能当子类用
常见错误是把 Modifier 当成 Element 的子级来写,比如 header__logo--small —— 这里 --small 看似修饰 logo,但它实际是 header__logo 这个完整类名的 Modifier,不是 logo 的子类。所以它必须和 header__logo 并列出现在 class 属性里,不能替代它。
- ✅ 正确:
class="header__logo header__logo--compact" - ❌ 错误:
class="header__logo--compact"(丢失基础类,样式无锚点) - ❌ 错误:
class="header__logo header__logo__icon--bold"(__icon是合法 Element,但__icon--bold是非法结构 —— Modifier 只能挂 Block 或 Element,不能挂 Element 的 Element)
最容易被忽略的一点:Modifier 类名是否合法,不取决于你“觉得像不像”,而取决于它能否被 stylelint-selector-bem-pattern 正则识别。漏一个 _ 或错用 - 替代 --,CI 就该报错——这不是格式洁癖,是保障整个团队 CSS 可追溯、可搜索、可自动化的底线。


















