你以为 MPA 跳转就只能忍着白屏?今天这件事被三行 CSS 彻底原生化了

每次点一个链接,页面就闪一下白屏——这事儿从互联网诞生那天起就没断过。多页应用(MPA)每次导航都要经历:浏览器销毁当前页面 DOM → 发起请求 → 等 TTFB → 解析 → 渲染。用户眼睁睁看 200~800ms 的空白,这在 SPA 时代被当作「活该忍受的代价」。

结果这个代价在 2026 年被正式取消了。

三行 CSS,浏览器自己搞定跨页面过渡

Chrome 126(2024 年中)和 Safari 18.2(2025 年初)先后支持了跨文档视图过渡(Cross-Document View Transitions),整个 MPA 导航动画变成了纯 CSS 声明:

/* 在两个页面都加上这两行 */
@view-transition {
  navigation: auto;
}

没了。就这么多。

用户点击同一个域下的链接时,浏览器自动:

  1. 给当前页面拍一张快照
  2. 加载新页面(在屏幕外渲染)
  3. 给新页面再拍一张快照
  4. 在两张快照之间做交叉淡化动画
  5. 把快照换成真实页面

整个过程用户看到的不是白屏,是平滑过渡。不用写一行 JavaScript,不需要任何框架。

元素变形:让缩略图「飞」进详情页

默认是全页交叉淡化,但如果两个页面上有同一个元素(比如列表页的缩略图和详情页的大图),给它们起一样的名字,浏览器就会自动让这个元素在两个位置之间「变形」而不是整页淡入淡出:

/* 列表页 */
.product-thumb {
  view-transition-name: product-hero;
}

/* 详情页 */
.product-image {
  view-transition-name: product-hero;
}

点击列表里的产品图,它会自己计算位置和尺寸差,然后流畅地「飞」到详情页的 hero 区域。

Safari 官方演示里,Navigation API 配合 pageswap/pagereveal 事件可以做到更深度的状态保持——比如视频在页面跳转后继续播放,滚动位置精确还原。这在过去需要整个 SPA 架构才能实现。

前进/后退可以不一样

用 navigation 类型区分前进和后退,分别写动画方向:

html:active-view-transition-type(forwards) {
  ::view-transition-old(root) { animation: 240ms ease-out slide-out-left; }
  ::view-transition-new(root) { animation: 240ms ease-out slide-in-right; }
}
html:active-view-transition-type(backwards) {
  ::view-transition-old(root) { animation: 240ms ease-out slide-out-right; }
  ::view-transition-new(root) { animation: 240ms ease-out slide-in-left; }
}

配合 pageswap 事件判断导航方向即可。这在 SPA 里是标配,在 MPA 里用 CSS 就能做。

四个必须知道的坑

第一,必须同源。协议、域名、端口任一不同都直接静默失效,两个页面都声明了 @view-transition 但没有动画?先查是不是跨域了。

第二,4 秒超时。Chrome 的视图过渡在导航开始后 4 秒内必须完成,否则直接抛 TimeoutError 并以普通页面加载收尾。用户网速慢的时候动画会直接消失。解决方案是配合 Speculation Rules API 提前预取下一页,让加载时间压到 4 秒以内。

第三,view-transition-name 不能重复。同一页面上两个元素用了同一个名字,过渡直接跳过这两个元素,不报错,只是什么都没发生。动态列表要动态生成唯一名字:

// pageswap 事件里动态命名
window.addEventListener(pageswap, (e) => {
  if (!e.viewTransition) return;
  const card = getClickedCard();
  card.style.viewTransitionName = `card-${card.dataset.id}`;
});

第四,动画拉伸。伪元素的 object-fit 默认是 fill,图片会变形。加一句 object-fit: cover 修掉这个问题。

无障碍优先

所有用户都该看到这个动画吗?不一定。视图过渡本质上是运动:

@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}

这个查询不是可选项。用户明确要求减少运动时,浏览器直接回退到普通页面加载,什么都不展示。没有这个查询等于对所有用户强行动画。

2026 年能上生产了吗

可以,但作为渐进增强。Chrome + Edge + Safari 三家主流浏览器全部支持,Firefox 还在 behind flag。如果你的用户里有大量 Firefox 用户,他们会看到正常页面加载而不是动画,不会报错,不会白屏,什么都不影响。

现在打开任何一个多页站点,在 global stylesheet 里加两行 CSS,马上就能看到效果。最保守的方案也是零风险的。

下一步

如果想做得更完整:

  • 配合 Speculation Rules API 预取下一页,把加载时间压缩到 0ms
  • 用 pageswap/pagereveal 事件做 just-in-time 命名,避免静态命名污染
  • 给前进/后退分别写不同方向的滑动动画
  • 在 DevTools Animations 面板里慢放到 25% 一帧帧看过渡在干什么

SPA 框架之所以存在,很大程度上是因为 MPA 的交互体验太割裂。2026 年这个理由消失了。

评论区

0 条评论

登录后可评论。

阿柯·前端架构 14 阅读