原生CSS嵌套需显式使用&或@nest,省略&、BEM拼接(如&__item)、嵌套内媒体查询套媒体查询均非法;&仅支持拼接和伪类,复杂关系必须用@nest。

原生 CSS 嵌套已正式进入主流浏览器(Chrome 116+、Firefox 124+、Safari 17.4+),但直接把 .scss 文件里的嵌套代码“原样复制粘贴”到 .css 中,大概率会失效或产生意外选择器。关键不是“能不能写”,而是“怎么写才被解析为预期的 CSS”。
必须显式使用 &,不能省略
SCSS 允许你省略 & 写 .card { .title { ... } },这在原生 CSS 中是非法语法,会被整个规则忽略(浏览器 DevTools 里直接标红或静默丢弃)。
-
.card { .title { color: red; } }→ ❌ 无效,不生效 -
.card { & .title { color: red; } }→ ✅ 解析为.card .title -
.card { &:hover { ... } }→ ✅ 正确,&:hover是完整且推荐的写法 -
.card { &-header { ... } }→ ✅ 解析为.card-header(仅限后缀拼接,不支持&__item)
@nest 是处理复杂关系的唯一出路
当你需要表达“父元素的兄弟”“某类祖先下的当前元素”这类 SCSS 里靠上下文推断的关系时,& 不够用。比如 SCSS 中常见的:
.nav { + .header { margin-top: 1rem; } }
这个 + .header 在原生 CSS 中不能写成 & + .header(它会被解析为 .nav + .header,看似一样,但语义错位:原意是“当前 .nav 后紧跟的 .header”,而 & + .header 实际上等价于独立选择器,失去嵌套上下文约束)。正确解法是:
立即学习“前端免费学习笔记(深入)”;
- 用
@nest显式声明嵌套关系:@nest .nav + .header { margin-top: 1rem; } -
@nest后必须跟一个完整、合法的选择器,且该选择器中至少有一个部分与外层选择器匹配(如.nav或其祖先/后代) - 不支持
@nest嵌套在媒体查询内部再套媒体查询(会报错)
媒体查询和伪类嵌套写法一致,但优先级更敏感
媒体查询可以嵌套,写法和 SCSS 几乎一样,但要注意:嵌套后的规则优先级由最终生成的选择器决定,不是“看起来缩进更深就更高”。
-
.button { @media (prefers-reduced-motion) { animation: none; } }→ ✅ 生成@media (prefers-reduced-motion) { .button { animation: none; } } -
.button { &:hover { @media (hover: hover) { background: #eee; } } }→ ✅ 生成.button:hover@media (hover: hover) { ... },注意这是两个条件同时满足 - 避免写
.card { @media (min-width: 768px) { &__content { ... } } }→ ❌&__content不合法,必须写成& .card__content或改用@nest
BEM 类名拼接要手动补全,没有自动转换
SCSS 的 &__element 在原生 CSS 中不被支持。浏览器不会把 &__element 当作字符串拼接操作,它只是个非法选择器。
-
.card { &__header { ... } }→ ❌ 解析失败 - 必须显式写出:
.card { & .card__header { ... } }或.card { @nest .card__header { ... } } - 如果项目重度依赖 BEM,建议保留构建时预处理(如 PostCSS 插件),或接受手写冗余——原生嵌套不解决命名约定问题,只解决作用域组织
最易被忽略的一点:原生嵌套不改变选择器特异性(specificity)计算方式。你在嵌套块里写的 & .child 和外面单独写的 .parent .child 完全等价,不会因为缩进就“变重”或“变轻”。别指望靠嵌套来 hack 权重。


















