必须显式声明块选择器,&__element和&--modifier才正确输出BEM类名;否则会生成语义错误的选择器,如.modal .overlay__header;嵌套超三层说明组件职责未切开,应改用平级BEM类名。

直接用 &__element 和 &--modifier,但必须确保 & 的父级是块名本身,否则编译出的选择器语义就错了。
嵌套前必须显式声明块选择器
Less 的 & 不会自动“猜”你想要的块名,它只忠实地代表当前选择器的完整父级。如果漏掉顶层块声明,&__header 就可能变成 .modal .overlay &__header → 编译为 .modal .overlay__header,这已经不是 BEM,而是 DOM 结构快照。
- ✅ 正确写法:
.card { &__header { padding: 1rem; } }→ 输出.card__header - ❌ 错误写法:
.card { .header { &__title {} } }→ 输出.card .header__title,破坏“一个元素只属于一个块”原则 - 块名不能靠变量拼接替代作用域:
@block: "card"; .@{block}__header {}生成的是平级类,丢失与.card的样式继承和上下文约束
修饰符必须绑定到块或元素,不能独立存在
BEM 的 --modifier 是状态开关,不是孤立样式片段。单独定义 .card--hover 看似简洁,但一旦被其他父级(比如 .list .card--hover)意外命中,权重和语义全乱。
- ✅ 推荐写法:
.card { &--disabled { opacity: 0.5; pointer-events: none; } }→ 输出.card--disabled,权重稳定,可与其他修饰符组合(如.card--featured.card--disabled) - ✅ 状态联动写法:
.card { &:hover { &--hover { transform: translateY(-2px); } } },保证.card--hover只在 hover 触发时生效 - ❌ 避免:
.card { .card--hover { ... } }→ 输出.card .card--hover,权重翻倍且无法脱离父级使用
嵌套层级超过 3 层,说明结构该拆了
当你写出 .dialog { .body { .content { .text { font-size: 14px; } } } },这不是嵌套技巧问题,是组件职责没切开。BEM 要求每个视觉单元都有独立、扁平的类名,而不是靠 CSS 层级模拟 DOM 深度。
- 应改为:
.dialog__body { ... }、.dialog__content { ... }、.dialog__text { ... },全部平级定义 - 嵌套只用于状态组合(如
&--expanded &__content),不用于模拟 DOM 树 - Chrome DevTools 在嵌套超 4 层后,源码映射基本失效,调试时找不到对应 Less 行号
真正容易被忽略的是:BEM 类名不是为了“看起来结构清晰”,而是为了隔离作用域、控制权重、支持组合复用。嵌套只是减少重复敲块名的辅助手段,不是结构设计本身——块名写在哪一行,决定了 & 绑定到谁,也决定了最终 CSS 是否还能被安全覆盖和维护。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











