@at-root 是生成 bem 类名的唯一安全方式,必须跳出嵌套上下文在根层级拼接,否则 &__xxx 会编译出带空格的后代选择器,导致样式失效或语义错乱。

为什么&__item会编译出带空格的后代选择器
SCSS 的 & 表示“当前完整选择器字符串”,不是“块名”。在 .card { &__title { } } 中,& 确实是 .card,但嵌套机制默认加空格,结果是 .card .card__title——合法 CSS,但违背 BEM 单类名原则。DOM 里只写 class="card__title",样式完全不生效。
更危险的是嵌套在伪类或子容器中:.button { &:hover { &__icon { } } } 编译为 .button:hover__icon,浏览器直接忽略;.sidebar .widget { &__header { } } 变成 .sidebar .widget__header,语义错乱。
@at-root 是唯一安全生成 __ 和 -- 类名的方式
必须跳出嵌套上下文,在根层级拼接。所有 __ 和 -- 类名都得和块定义同级,不能嵌套进状态、容器或媒体查询里。
-
.card { @at-root #{&}__title { color: #333; } }→ 输出.card__title -
.card { @at-root #{&}--loading { opacity: 0.7; } }→ 输出.card--loading - 变量也适用:
$block: "button"; @at-root #{$block}__icon { … } - 禁止在
&:focus、@media内部再用@at-root #{&}__xxx,输出顺序不可控且破坏语义
@at-root 默认只跳出选择器嵌套,不跳出 @media 或 @supports
默认 @at-root 等价于 @at-root(without: rule),只解除父选择器嵌套,对媒体查询无影响。
-
@media (min-width: 768px) { .card { @at-root .card__body { } } }→ 输出@media (min-width: 768px) { .card__body { } },仍在媒体查询内 - 要彻底提级到全局顶层,需显式指定:
@at-root(without: media rule) -
@at-root(without: all)可跳出所有上下文(含@media、@supports、@layer),但慎用,易导致样式顺序失控
用 @at-root 提级工具类或兄弟组件样式,避免冗余前缀
当逻辑上不属于当前组件,却硬塞进嵌套时,会产出像 .modal .u-text-center 这种冗余选择器。实际只需要 .u-text-center。
-
@at-root .u-text-center { text-align: center; }→ 输出.u-text-center - 可控提级:
@at-root (with: .theme-dark) { .button { color: white; } }→ 输出.theme-dark .button - 别在
@media内写.card { &__body { } }:外层若还有嵌套,&会展开全部路径,生成不可控长选择器
@at-root 不是语法糖,而是明确告诉 Sass:“这段样式不属于当前嵌套路径”。漏掉它,就等于把 BEM 类名交给了嵌套引擎随机拼接——看似省事,实则埋下运行时失效和调试黑洞。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











