less中的&仅是编译期字符串拼接占位符,不理解bem语义,仅支持.btn{&--primary}、.card{&__header}、.btn{&:hover}三类合法位置,误用会导致非法选择器或编译失败。

Less里的&不是BEM语法糖,它只是拼接字符串的编译期占位符;想靠它自动生成.btn--primary或.card__title,必须严格匹配BEM层级和空格规则,否则产出的是错位选择器甚至编译失败。
为什么&拼出来的类名经常不对
根本原因在于&只做字面拼接,不理解BEM语义。它不会自动区分修饰符--、元素__或状态前缀,全靠你手写符号位置。
-
.btn { &--primary { ... } }→ 编译为.btn--primary,正确 -
.btn { &__icon { ... } }→ 编译为.btn__icon,也正确 -
.btn { &--large__icon { ... } }→ 编译为.btn--large__icon,但BEM规范里这属于非法嵌套(修饰符不能带元素),实际应写.btn--large .btn__icon或.btn__icon--large - 漏掉空格:
.btn{&--primary{}}(&和--紧贴)→ 多数Less版本报ParseError或静默忽略
&在BEM中该用在哪几个固定位置
BEM结构只有三类合法拼接点,&只应在这些位置出现,其他地方硬套反而破坏可维护性。
- 修饰符:写在父类后加
--,如.btn { &--disabled { opacity: 0.5; } }→.btn--disabled - 元素:写在父类后加
__,如.card { &__header { padding: 1rem; } }→.card__header - 伪类/伪元素:必须用
&:或&::开头,如.btn { &:hover { transform: translateY(-1px); } }→.btn:hover - 别在媒体查询里直接用
&:@media (max-width: 768px) { & { ... } }会报错;得先定义外层选择器,再进查询块里用&
哪些BEM场景坚决不能用&
一旦脱离“父类名+固定连接符”这个简单模式,&就不再可靠,此时应退回到显式命名。
- 动态主题类:如
.header.theme-dark下想定义.header__title,写.header { &__title { ... } }只能生成.header__title,无法继承.theme-dark——它不认运行时类,只认源码里写的.header - 跨组件复用元素:比如
.modal__close和.drawer__close都需相同样式,用&__close就得在两个父块里各写一遍;不如直接定义原子类.close-btn - 需要后代关系时:BEM中
.card__body .card__title是合法的,但.card__body { & .card__title { ... } }会生成.card__body .card__title(看似对),可一旦.card__body本身被动态移除,整个规则就失效;显式写更稳 - 多个并列父选择器共用一套子规则:
.btn, .link { &__icon { ... } }→ 只绑定到.link,.btn被忽略;&永远只认最近一个父级
构建时容易被忽略的隐性陷阱
即使&写法全对,输出的CSS仍可能在构建链路里被二次破坏。
- 压缩工具(如
cssnano)默认开启reduceTransforms,会把.btn--primary:hover这种长选择器判为低优先级而删掉;必须显式配置reduceTransforms: false - Webpack +
less-loader不报嵌套深度警告,但Chrome DevTools里看到.a .b .c .d:hover这种7层选择器时,基本就是&被滥用+缩进嵌套叠加的结果 - 和原生CSS嵌套(
@nest)混用会出问题:.card { @nest &__title { ... } }是浏览器原生语法,.card { &__title { ... } }是Less编译语法,两者输出结果不同,构建工具也不会自动转换
真正难的不是写出&--primary,而是判断什么时候该让&退场——当父选择器开始带条件类、跨模块复用、或需要响应式拆分时,老老实实写.btn--primary比在嵌套里绕三圈更安全。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











