你以为 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;
}
没了。就这么多。
用户点击同一个域下的链接时,浏览器自动:
- 给当前页面拍一张快照
- 加载新页面(在屏幕外渲染)
- 给新页面再拍一张快照
- 在两张快照之间做交叉淡化动画
- 把快照换成真实页面
整个过程用户看到的不是白屏,是平滑过渡。不用写一行 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 年这个理由消失了。
评论区
登录后可评论。