直接写 &__element 会失效,因为 & 只展开为最近父选择器字符串,不感知 bem 语义层级,导致修饰符、混入或变量场景下类名错误;应改用 bem() 函数或 block() 混入动态生成类名。

为什么直接写 &__element 会失效?
很多人在 Sass 中写 BEM 时,下意识写成这样:
.card {
&__title { color: #333; }
&__content { padding: 1rem; }
}
结果编译出来是 .card__title 和 .card__content——看起来没错,但一旦遇到修饰符(--hover、--disabled)或嵌套组件(比如 .card__header .card__title),这种写法就暴露问题:它完全依赖父选择器名称字面拼接,无法区分“当前作用域的块”和“外部传入的块名”。
真正的问题在于:& 只展开为**最近一层的父选择器字符串**,不感知 BEM 的语义层级。如果你把 .card 抽成变量或混入(@mixin),&__title 就会崩。
用 @function + @each 动态生成 BEM 类名
更可控的方式是把块名作为参数传入,用函数拼接,避免硬编码和 & 的歧义:
@function bem($block, $element: null, $modifier: null) {
$result: $block;
@if $element { $result: $result + '__' + $element; }
@if $modifier { $result: $result + '--' + $modifier; }
@return $result;
}
.card {
{bem('card', 'title')} { font-weight: bold; }
{bem('card', 'content', 'expanded')} { max-height: 300px; }
}
这样编译后是 .card .card__title 和 .card .card__content--expanded,结构清晰,且 bem() 可复用于其他块(如 bem('button', 'icon'))。
- 必须用
{...}而不是&__...,否则插值不生效 -
$block建议统一用字符串字面量(如'card'),不要传变量名,避免命名冲突 - 该函数不处理多级元素(如
card__header__title),BEM 规范本身也不鼓励这种写法
修饰符类名必须独立声明,不能靠 &--mod 硬套
常见错误是这么写:
.card {
&--featured { background: gold; }
&__title { color: #222; }
&__title&--featured { color: #fff; } // ❌ 编译为 .card__title.card--featured
}
这违反 BEM 原则:修饰符应作用于块本身,而非元素。正确做法是让修饰符显式影响子元素:
.card {
&--featured {
background: gold;
&__title { color: #fff; } // ✅ 编译为 .card--featured .card__title
}
&__title { color: #222; }
}
-
&--featured __title这种写法在 Sass 中合法,但语义上是“块修饰符作用域下的元素”,不是“元素自身的修饰符” - 如果真需要元素修饰符(如
card__title--large),应单独定义,不要嵌套在块里,否则难以复用 - 注意 CSS 选择器权重:嵌套生成的
.card--featured .card__title比.card__title--large权重低,覆盖逻辑更可控
用 @mixin 封装带命名空间的 BEM 块更安全
当项目中多个组件共用相似结构(比如都含 __header、__body),可抽象为混入:
@mixin block($name) {
.#{$name} {
&__header { margin-bottom: 0.5rem; }
&__body { line-height: 1.6; }
&--compact &__body { padding: 0.25rem; }
}
}
@include block('alert');
@include block('panel');
这样既避免重复写 .alert {...},又确保每个块的 BEM 类名严格隔离。
- 混入内不推荐用
&去拼接跨块的类(如&__footer在block('alert')里),容易误生成.alert__footer而非预期的.footer - 若需组合多个块(如
alert__icon+icon--warning),建议用@extend或 utility class,别强塞进 BEM 嵌套 - Sass 5.0+ 支持
@use,把bem()函数和block()混入放到单独文件(如tools/_bem.scss),再@use 'tools/bem',避免全局污染
BEM 的“优雅”不在嵌套多深,而在类名生成逻辑是否可预测、可追溯、不依赖上下文字符串拼接。父选择器符号 & 是快捷键,不是 BEM 的基础设施;一旦组件开始复用或主题化,就得靠函数和混入把命名权收回来。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











