不能写万能 bem() 混合宏,因其易产出非法类名(如.card__hover)、破坏 BEM 作用域约束、无法保证 & 提级语义,且调试困难;应拆分为 b()、e()、m() 三个独立 mixin,统一用 @at-root 提级并变量化分隔符。

直接用单个 @mixin bem($block, $element, $modifier) 封装 BEM 是危险的——它会产出非法类名、破坏嵌套语义、调试时根本找不到对应 CSS 规则。
为什么不能写万能 bem() 混合宏
参数顺序一错,生成的类名就完全不对。比如 @include bem('card', 'header') 和 @include bem('card', null, 'hover') 看似只是传参差异,实际编译结果分别是 .card__header 和 .card--hover;但若内部 @if 判断不严密,很容易产出 .card__hover 这种非法名。
更关键的是,BEM 要求 .card__header 必须在 .card { } 作用域内定义,否则无法保证样式隔离;而单 mixin 返回的是扁平选择器,& 在里面根本不起作用。
- 修饰符挂载位置错误:比如想表达
.card--large .card__body,单 mixin 很可能拼出.card--large__body - 无法约束调用层级:
e()必须出现在b()内部,单 mixin 没法强制这个关系 - 分隔符(
__、--)硬编码在 mixin 里,改起来要全局搜索
b()、e()、m() 三个独立混合宏怎么写
每个只干一件事,且全部依赖 @at-root 提级,避免编译出带空格的后代选择器。
基础配置统一声明:
$namespace: "n"; $element-separator: "__"; $modifier-separator: "--";
三个核心 mixin:
@mixin b($block) {
$B: #{$namespace}-#{$block};
.#{$B} { @content; }
}
@mixin e($name) {
@at-root #{&}#{$element-separator}#{$name} { @content; }
}
@mixin m($name) {
@at-root #{&}#{$modifier-separator}#{$name} { @content; }
}
-
b()必须先执行,它设定了&的值,后续e()和m()才能正确引用 -
e()和m()都必须用@at-root提级,否则会编译成.card .card__header这类带空格的选择器 - 所有分隔符必须统一定义为变量,禁止在 mixin 体内硬写
"__"
修饰符 + 元素组合的合法写法
BEM 允许 .card--large .card__header,但禁止 .card--large__header。遇到这种组合,不能在 m() 里再 @include e()——那会直接产出非法名。
正确做法是分开声明:
@include b("card") {
@include m("large") {
// .card--large 样式
}
@include e("header") {
// .card__header 样式
}
// 单独写组合规则(如需要)
&--large &__header {
// .card--large .card__header
}
}
- 禁止在
m()或e()内部嵌套另一个e()/m() - 组合场景(如状态影响子元素)应显式写出
&--large &__header,而非靠 mixin 自动拼接 - 如果大量使用组合,说明组件粒度可能过粗,该拆分子组件了
循环生成 BEM 类名时插值怎么写才不报错
@each $modifier in ("hover", "disabled") 中的字符串必须加引号,否则 SCSS 会把 hover 当作未定义变量,报 Undefined variable "$hover"。
错误写法:
@each $modifier in (hover, disabled) { ... }
正确写法:
@each $modifier in ("hover", "disabled") {
@at-root #{&}#{$modifier-separator}#{$modifier} {
// .card--hover
}
}
- 修饰符列表必须是字符串字面量数组,不能省略引号
-
#{$modifier}本身不带引号,但$modifier的值必须是带引号的字符串 - 从
map-keys($modifiers)取值时,需确保 map 的 key 是字符串类型,否则仍需额外转字符串
真正容易被忽略的是:BEM 的解耦效果不来自 SCSS 语法糖,而来自对类名显式归属的强制约束。哪怕 mixin 编译完全正确,只要 HTML 漏写一个 card__title 或多套一层 card--featured card__title,整个样式链路就断了——DOM 上少一个 class,比逻辑错误更隐蔽。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











