CSS原生嵌套语法来了,还需不需要预处理器?
结论:对大多数新项目来说,原生 CSS 嵌套已经可以替代 Sass 的"嵌套"这一项功能了;但预处理器并没有过时——只要你还需要 mixin、循环、函数、选择器插值,或者要兼容老内核浏览器,它就还有位置。最实用的路线是:用原生嵌套的语法写代码,用构建工具负责降级。
原生嵌套现在到底能不能直接用
结论:能用,而且从 2023 年起已经是三大引擎都支持的 Baseline 特性。
具体版本:Chrome/Edge 112(2023 年 4 月)、Safari 16.5、Firefox 117 先后支持 CSS Nesting,到 2023 年底已经可以放心在生产环境使用。国内常见的微信/QQ 内置浏览器大多基于较新的 Chromium 内核,一般没问题;真正需要警惕的是老旧安卓 WebView 和还在跑几年前内核的定制浏览器。
写法和 Sass 很像:
.card {
padding: 16px;
& .title { font-weight: 700; }
&:hover { box-shadow: 0 2px 8px rgb(0 0 0 / .12); }
@media (min-width: 768px) { padding: 24px; }
}
注意最后一行:原生嵌套里 `@media` 可以直接嵌在选择器内部,不用像早期写法那样先写 `&`。这是原生方案比预处理器更顺手的地方——DevTools 里看到的就是你写的结构,不需要 source map 反查。
有两个坑,从 Sass 迁过来必踩
第一个坑,也是最重要的:原生 `&` 的语义等价于 `:is(父选择器)`,不是字符串拼接。
/* 原生 CSS */
.a, .b { & .c { color: red; } }
/* 实际等价于 */
:is(.a, .b) .c { color: red; }
/* Sass 输出的是 */
.a .c, .b .c { color: red; }
差别在优先级上:`:is()` 取参数列表里最高的那个权重。如果 `.b` 本身是个更复杂的选择器,整条规则的权重会被拉高,可能压过你原本以为会生效的样式。迁移时如果发现"样式突然盖不住了",先查这里。
第二个坑:早期实现的嵌套规则不能以类型选择器(标签名)开头。`div { p { ... } }` 在老版本里会被当成普通声明解析失败。后来规范放宽了(Chrome 120 起支持),但为了兼容更广的浏览器,写 `& p` 或 `& h2` 更稳。
另外提醒一句:嵌套层级别超过 3 层。原生嵌套让深层结构写起来太容易,最后生成一堆权重高得离谱的选择器,后期只能靠 `!important` 打补丁。
预处理器还剩下哪些不可替代的能力
结论:mixin、函数、循环、选择器插值、模块系统,这五样原生 CSS 至今没有等价物。
- mixin / 函数 / 循环:Sass 的 `@mixin`、`@function`、`@each` 可以批量生成断点、间距、色阶。CSS 侧的 `@custom-media`、`@when/@else` 还在提案阶段,没有落地。
- 选择器插值:`#{$prefix}__title` 这种动态拼选择器,原生做不到。
- 模块拆分:`@use` / `@forward` 的 partials 体系,比原生 `@import` 好用得多(后者是运行时请求,性能差,即便 HTTP/2 下也不推荐)。
不过要公平地说,CSS 这几年补上了不少原本靠预处理器做的事:自定义属性替代变量,`@layer` 管理层叠顺序,`color-mix()`、`clamp()`、`:is()`/`:where()` 处理颜色、尺寸和选择器复用。真正还缺的,基本就是"批量生成"这一类能力。
什么项目可以彻底扔掉预处理器
结论:中小型项目、后台系统、模板主题这类"没有复杂设计系统"的场景,直接上原生嵌套完全够用。
典型的例子是那种上传即用、没有 Node 构建链的项目——像 Clara BBS 这种无框架轻量 PHP 社区系统,本身主打"无需 Composer、无需命令行、无编译缓存、保存即生效",主题样式改一行就立刻看到效果。给这类系统写模板 CSS 时再引入一套 Sass 编译流程,属于给自己加负担,原生嵌套能把代码组织得很干净。
反过来说,如果你在做组件库、设计系统,需要按 token 批量生成几万行工具类,或者团队已有大量 Sass 代码和历史依赖,那迁移的收益远小于成本,继续用就行。
要兼容旧浏览器:折中方案
结论:用原生语法写,构建期交给 PostCSS 或 Lightning CSS 转译,两头的好处都能拿到。
具体做法:引入 `postcss-preset-env` 或 Lightning CSS,开启 nesting 相关的转译插件,浏览器目标设成 `> 0.5%, last 2 versions, not dead`。你写原生嵌套,构建产物自动展开成扁平选择器,老浏览器也能跑。Vite、esbuild 用户基本开箱就有一条 CSS 处理管线,加个配置即可。
最后收一下:原生嵌套解决的是"代码组织"问题,预处理器解决的是"代码生成"问题。前者现在浏览器自己会了,后者还没有。所以别问要不要二选一,先想清楚你项目里到底有没有"批量生成"的需求——没有,就大胆用原生;有,就留着预处理器,或者用构建工具在两者之间搭桥。
转载请注明出处,版权归原作者所有。
星耀SVIP
管理员
黑卡会员





