bem禁止修饰符连写如.modal--open--loading,须用单一主导修饰符(如.modal--open)加data属性承载次要信息(如data-modal-source="form-submit")。

修饰符互斥时不能连写,比如 .modal--open--loading
BEM 明确禁止用多个 -- 连续叠加修饰符。像 .modal--open--loading 这种写法语义混乱:它既不是“打开且加载中”的并列状态,也不是可预测的组合逻辑,而是把两个互斥状态强行拼在一起。浏览器能解析,但人无法快速判断优先级、JS 无法安全切换、CSS 也无法做原子化覆盖。
常见错误现象:
- 开发时手动拼接字符串:
className={`modal--${isOpen}--${isLoading}`},结果生成modal----loading或空连字符 - 在 SCSS 中用嵌套 +
&--loading误套在&--open内部,编译出非法类名 - 测试时发现
.modal--open--loading样式没生效,查半天才发现规则写的是.modal--loading,压根没匹配上
主状态用单一主导修饰符,次要信息交给 data- 属性
真正需要表达“当前是打开态,同时加载中”这类复合意图时,应由一个主导修饰符定基调,其余上下文交由 data- 属性承载,CSS 不参与判断。
推荐做法:
- 主导修饰符只选一个:
.modal--open(表示可见性)或.modal--loading(表示操作态),二者不共存 - 加载原因、来源等辅助信息用
data-:data-modal-pause-reason="timeout"、data-modal-source="form-submit" - JS 根据这些属性做逻辑分支,CSS 只响应明确的修饰符,保持样式层纯粹
这样既避免类名爆炸,又让 DOM 状态可读、可调试、可被自动化工具识别。
多个视觉变体共存时,改用组合类而非连写修饰符
如果真有多个视觉属性需同时生效(比如按钮既要 --primary 又要 --small),它们必须是正交、可叠加的,且都作用于同一 block,此时允许写成 .button--primary.button--small,而不是 .button--primary--small。
关键区别:
-
.button--primary--small是非法 BEM —— 它暗示存在一个叫 “primary-small” 的新修饰符,语义不可拆分 -
.button--primary.button--small是合法组合 —— 每个修饰符独立定义,CSS 规则互不干扰,支持任意排列 - SCSS 中应分别定义:
.button--primary { ... }和.button--small { ... },不嵌套
注意:这种组合只适用于纯视觉变体,不能用于业务状态(如 --submitted 和 --error 仍互斥,不能共存)。
为什么不能靠 CSS 优先级解决互斥问题
有人试图用更具体的选择器覆盖,比如写 .modal--open.modal--loading { opacity: 0.7; } 来“兜底”,但这会带来三个实际麻烦:
- 类名本身已违反 BEM,CI 工具(如
stylelint-selector-bem-pattern)会直接报错阻断提交 - JS 切换状态时必须同步增删两个类,漏一个就导致样式残留或错乱
- DevTools 里看到
.modal--open--loading,根本看不出它是“open + loading”,还是某个旧版本遗留的特殊状态
真正难的不是写对类名,而是在每次加修饰符前,先问一句:“这个状态是否可能和另一个同时存在?如果会,它是不是该降级为 data- 或拆成独立 block?”
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











