BEM规范禁止块内嵌套块时拼接类名,子块必须保持独立完整类名(如.button),不可写为.search-form__button;判断标准是该UI单元是否具备复用性、独立状态及行为。

块内嵌套块,类名不拼接、不加前缀
块可以自由嵌套在另一个块内部,但子块的类名必须保持独立、完整,不能带上父块前缀。比如 .search-form 里放一个 .button,按钮类名就是 .button,不是 .search-form__button——后者是元素,而 .button 是独立可复用的 Block。
常见错误现象:.card__user-avatar 被当成元素写,但 .user-avatar 实际有自己尺寸、交互、状态(如 loading / error),且在用户列表、弹窗、评论区多处复用——它就该是 Block,不是 Element。
- 判断标准:这个 UI 单元是否在别处出现过?是否有自己的 JS 行为或 CSS 变体?如果是,必须抽成 Block
- HTML 中允许
<div class="card"><div class="user-avatar"></div></div>,这是完全合法的嵌套结构 - SCSS 中也应分开写:
.card { }和.user-avatar { }各自文件,用@use引入,不嵌套编译 - 禁止写
.card { & .user-avatar { } },这会生成后代选择器,破坏样式隔离
什么时候该用 Modifier 而不是新块?
当视觉单元不具备独立功能边界,只是对现有块的轻量变体时,优先用 Modifier,而不是硬拆新 Block。例如 .button--in-card 比新建 .card-button 更合理——前提是它仅改变 padding、font-size 等上下文适配样式,不引入新逻辑。
容易踩的坑:.button--in-card 如果后续要支持 hover 动画、disabled 状态、图标位置切换,就说明它已超出 Modifier 承载能力,应回退为独立 Block。
立即学习“前端免费学习笔记(深入)”;
- Modifier 应只表达有限、可枚举的状态:主题、尺寸、位置、禁用等
- 不要用 Modifier 补语义缺口,比如
.card__header--with-title是错的——.card__header本不该有子元素命名权 - Modifier 不解决复用问题,只解决“同一块在不同场景下微调”的问题
SCSS 嵌套中如何安全处理块内块?
SCSS 本身不禁止嵌套,但 BEM 约束的是最终生成的 CSS 类名和选择器结构。只要编译后不产生 .card .button 这类后代选择器,嵌套就是安全的;一旦用了空格,就等于放弃 BEM 隔离性。
正确写法只有一类:.card { &__title { } &__body { } },即仅嵌套本块的 Element 和 Modifier。子块必须在顶层声明。
- 禁止:
.card { .button { } }或.card { & .button { } }—— 编译出后代选择器 - 禁止:
.card { &__header { .title { } } }——.title若是独立 Block,就不该被锁在__header下 - 推荐:子块样式写在自己 SCSS 文件里,通过
@use "button"引入,.card只负责布局间距(如display: flex)
深层 DOM 结构下类名归属怎么定?
BEM 不看 HTML 嵌套深度,只看语义边界。哪怕 DOM 是 <div class="card"><div><div><div class="badge"></div></div></div></div>,只要 .badge 是独立 UI 单元,类名就还是 .badge,不是 .card__badge 或 .card__content__badge。
真正难的不是写对双下划线,而是每次加一层 div 时停下来问:这个节点有没有自己的复用场景?能不能脱离当前父结构存在?如果答案模糊,大概率是语义没理清,而不是命名不会写。


















