配了三年样式隔离,今天发现浏览器自己会了——@scope + @starting-style + light-dark() 把这件事彻底变了
我配了三年样式隔离,今天发现浏览器自己会了——@scope + @starting-style + light-dark() 把这件事彻底变了
以前配样式隔离要靠 BEM 命名规则,配入场动画要靠 JS 监听,配暗色模式要靠两套变量——三件事三个工具,每次接新项目都要从零搭起。
2026 年了,这三件事浏览器自己全包了。
@scope:样式隔离终于不用靠命名约定了
BEM 的本质是什么?是人为约定一个作用域边界,让样式不泄漏。但这件事 CSS 自己会做了。
@scope (.card) {
.title { color: blue; }
.body { font-size: 14px; }
}
写在 @scope 里的 .title 只在 .card 内部生效,出了这个范围无效。不需要 BEM 前缀,不需要 CSS Modules,不需要任何构建工具。Chrome 130+、Firefox 135+、Safari 18.4+ 全部支持,Baseline 2024。
那 BEM 什么时候还用得上?当你的”组件”边界和 DOM 节点不完全对齐的时候——这种情况越来越少见了。
@starting-style:元素生出来的第一帧终于能抓住了
CSS 动画有个经典问题:元素从 display: none 变成 display: block 的时候,第一帧是”空降”的,没有任何过渡。以前的解法是 visibility: hidden → visible + opacity: 0 → 1,但第一次渲染依然会跳。
@starting-style 就是来解决这个的:
.modal {
opacity: 0;
transform: scale(0.95);
transition: opacity 0.3s, transform 0.3s;
}
@starting-style .modal {
opacity: 0;
transform: scale(0.95);
}
浏览器会在元素”第一次显示出来”的时候,把 @starting-style 里的值当作起点。这样从无到有的第一次动画也能顺滑了。Chrome 117+ 支持,Firefox 暂时还在 behind flag。
light-dark():暗色模式终于不用写两遍了
暗色模式的标准流程是什么?配一套 CSS 变量,然后用媒体查询或 JS 检测系统主题,再切换变量值。两套变量,两个状态维护。
light-dark() 把这个变成一行:
background: light-dark(#ffffff, #1a1a1a);
color: light-dark(#000000, #f5f5f5);
light-dark(a, b) 接收两个值,第一个是亮色主题值,第二个是暗色主题值。浏览器根据系统主题自动选,不用写媒体查询,不用写 JS。
支持情况:Chrome 123+、Firefox 132+、 Safari 18+。主流浏览器全覆盖。
三件事一起用是什么体验
来看一个完整例子——一个卡片组件,样式隔离、入场动画、暗色模式全原生:
/* 样式隔离:@scope 代替 BEM */
@scope (.feature-card) {
:scope {
container-type: inline-size;
padding: light-dark(16px, 12px);
background: light-dark(white, #2a2a2a);
border-radius: 12px;
transition: box-shadow 0.3s;
}
.card-title {
font-size: 1.25rem;
color: light-dark(#1a1a1a, #f0f0f0);
}
.card-desc {
font-size: 0.9rem;
color: light-dark(#666, #aaa);
}
}
/* 入场动画:@starting-style 捕捉第一帧 */
.feature-card {
opacity: 0;
transform: translateY(16px);
transition: opacity 0.4s ease-out, transform 0.4s ease-out,
box-shadow 0.3s;
}
@starting-style .feature-card {
opacity: 0;
transform: translateY(16px);
}
三件事,没有 JS,没有构建工具,没有两套变量文件。一个 .card 的样式隔离靠 @scope,入场动画靠 @starting-style,暗色模式靠 light-dark(),三者互不干扰。
什么时候还要预处理器
不是说 SCSS/Less 就完全不用了。以下场景预处理器仍有价值:
- 循环和条件判断:CSS 没有原生 if/for,预处理器的循环在生成重复变体时仍有用
- 继承 @extend:跨组件的样式复用,@layer 可以部分替代但不能完全复制
- 函数式颜色运算:color-mix() 已经能覆盖大部分场景,但复杂的颜色变换链预处理器更灵活
其余 90% 的场景,2026 年的原生 CSS 已经够用了。
下一步
如果你现在在起一个新项目,试着先把 SCSS 卸掉,只用原生 CSS 写。三件事按顺序来:
- 先把变量迁移到 var() + @property
- 把嵌套改写成原生嵌套语法
- 把 BEM 组件的隔离层改成 @scope
迁移成本比你想象的低,依赖少了,构建也快了。
配了三年样式隔离,今天发现这三件事浏览器自己全包了——@scope 隔离样式,@starting-style 补动画第一帧,light-dark() 一行搞定暗色模式。预处理器能少装一个是一个。
评论区
登录后可评论。