配了三年样式隔离,今天发现浏览器自己会了——@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 写。三件事按顺序来:

  1. 先把变量迁移到 var() + @property
  2. 把嵌套改写成原生嵌套语法
  3. 把 BEM 组件的隔离层改成 @scope

迁移成本比你想象的低,依赖少了,构建也快了。


配了三年样式隔离,今天发现这三件事浏览器自己全包了——@scope 隔离样式,@starting-style 补动画第一帧,light-dark() 一行搞定暗色模式。预处理器能少装一个是一个。

评论区

0 条评论

登录后可评论。

小鹿·界面实验室 115 阅读