SCSS变量名和BEM块名必须分离,不能混用:块名是结构标识,应为字符串字面量(如"btn")且不参与计算;样式变量(如$btn-primary-bg)才用于颜色、尺寸等运算,二者语义不同、变更频率不同,硬绑定会放大维护成本。

SCSS变量名和BEM块名必须分离,不能混用
很多人试图用同一个变量既控制类名又控制样式值,比如定义$button后写.#{$button} { color: $button-color },结果改了变量名却漏掉 HTML class 或 Sass 类选择器,导致样式断裂。BEM 的类名是结构标识,不是样式配置项,二者语义不同、变更频率不同,硬绑定只会放大维护成本。
推荐做法是:用字符串字面量写块名(如"btn"),另用独立变量管样式(如$btn-color)。块名不参与计算,只用于拼接;样式变量才参与颜色、尺寸等运算。
- 块名变量应加
!default并带命名空间前缀:$block-btn: "ui-btn" !default - 样式变量命名带语义前缀:
$btn-primary-bg: #007bff,避免$primary这种全局泛称 - HTML 中必须显式写全类名:
class="ui-btn ui-btn--primary ui-btn__icon",不能靠 JS 动态拼接
@mixin b() 里别直接插值块名,用参数传入更安全
用@mixin b($block)封装 BEM 块时,如果内部直接用#{$block}拼类名,容易在嵌套调用中丢失上下文。比如@include b("card")被另一个 mixin 包裹时,$block可能被覆盖或作用域错乱。
真正可控的做法是让 mixin 只负责生成根选择器,块名由调用方传入,且不参与任何逻辑判断:
立即学习“前端免费学习笔记(深入)”;
@mixin b($block) {
$full-block: $namespace + "-" + $block;
.#{$full-block} {
@content;
}
}
-
$namespace统一定义在全局变量文件,比如$namespace: "xm" - 调用时明确传参:
@include b("button") { ... },不依赖外部变量状态 - 禁止在
@mixin内部对$block做字符串操作(如str-replace),Sass 字符串函数不可靠且难调试
元素和修饰符的分隔符必须显式声明,不能硬编码
写#{$block}__icon看着简单,但项目多人协作时,有人写__、有人写_、有人漏掉空格,最终 CSS 类名不一致。BEM 的__和--不是语法糖,Sass 不识别它们,全靠人控。
正确做法是把分隔符抽成变量,在一处定义、全局复用:
$element-separator: "__" !default;
$modifier-separator: "--" !default;
@mixin e($element) {
@at-root #{&}#{$element-separator}#{$element} {
@content;
}
}
- 避免在插值中直接拼
-active,它会被 Sass 当作减法运算;写成#{"-active"}或$modifier-separator + "active" - 分隔符变量必须带
!default,方便子项目覆盖(比如某些团队用_代替__) - 所有
@mixin e()和@mixin m()都基于这些变量,不接受原始字符串参数
HTML class 列表和 SCSS 输出必须人工对齐,工具无法自动校验
哪怕 SCSS 编译出完美的.ui-btn__label--large,如果 HTML 里只写了class="ui-btn__label"没加--large,样式就失效。这不是编译问题,而是结构契约断裂。
最容易被忽略的是:BEM 解耦效果不来自语法,而来自开发者的落地一致性。没有工具能强制 HTML 和 SCSS 同步更新。
- 组件文档必须明确列出所有合法 class 组合,例如:
ui-btn+ui-btn--primary+ui-btn__text - 禁止在 JS 中用
el.classList.add("ui-btn__text--bold")这种硬编码,应封装为addModifier("bold")方法 - CI 流程可加简单检查:扫描 HTML 文件中出现的
__/--类名,比对 SCSS 文件是否定义过对应规则


















