@at-root 是显式重置 CSS 输出层级的指令,非“退出嵌套”快捷键;滥用会破坏语义、升高 specificity 或导致样式失效。

@at-root 不是“退出嵌套”的快捷键,而是显式重置 CSS 输出层级的指令;滥用它会破坏选择器语义、升高 specificity、甚至导致样式不生效。
为什么 @at-root 生成的 .is-loading 仍被套在 .modal 里
常见错误现象:.modal { .is-loading { @at-root .is-loading { opacity: 0.5; } } } 编译后仍是 .modal .is-loading,没跳出。
- 根本原因:@at-root 后面的
.is-loading必须是**独立声明**,不能出现在已有嵌套块内部再套一层选择器;上面写法中.is-loading实际是嵌套在.modal下的子选择器,@at-root只作用于它自己那条规则,但前面的上下文已锁定作用域 - 正确写法是把
@at-root .is-loading { ... }单独提出来,写在.modal块外,或至少确保它不被包裹在任何父选择器内 - 如果真要在
.modal块里定义全局.is-loading,必须用@at-root (without: all) .is-loading { ... },否则媒体查询或@supports还可能把它卡住
@at-root (with: media) 和裸 @at-root 的关键区别
裸 @at-root 会把整条规则提到最外层,包括选择器本身;而 @at-root (with: media) 只动 @media,不动里面的选择器路径。
- 典型误用:
.btn { @at-root { @media (max-width: 768px) { &__icon { display: block; } } } }→ 编译后@media被提走,但&__icon失去上下文,可能变成孤立.btn__icon或解析失败 - 正确做法:
.btn { @at-root (with: media) { @media (max-width: 768px) { &__icon { display: block; } } } }→@media提到与.btn同级,&__icon仍能正确展开为.btn__icon - 注意:
with:后只能跟media、rule、all,写成with: screen或with: query会直接报错
BEM 场景下 @at-root 容易让 .block__element 变成 .block .block__element
在 .block { &__text { @at-root .block--theme-dark & { color: #eee; } } } 中,& 指向的是 .block__text,所以结果是 .block--theme-dark .block__text —— 看似合理,但实际已违反 BEM 扁平原则。
立即学习“前端免费学习笔记(深入)”;
- 问题在于:这个选择器依赖
.block--theme-dark必须和.block同级存在;若 DOM 中.block--theme-dark是加在 body 上的,那这条样式就失效 - 更安全的写法是显式写出完整类名:
@at-root .block--theme-dark .block__text { color: #eee; },避免依赖&的动态解析 - 尤其注意:不要在
@each循环里对&做嵌套 +@at-root组合,Sass 1.50+ 的局部变量(@let)在@at-root内部不可见
真正难的不是语法怎么写,而是判断“这个类到底该不该全局化”——@at-root 一旦用了,就等于放弃嵌套带来的作用域保护,后续维护时得靠人脑记住哪些类是“逃逸”的。这点容易被忽略,但代价最大。


















