View Transitions API 实战:跨页面/跨文档动画过渡方案

前端工程(更新于 2026年6月13日)

页面过渡的演进

方案 适用范围 实现复杂度 浏览器原生 性能
CSS transition 单组件
Framer Motion / GSAP SPA 路由
Shared Element Transition SPA + MPA
View Transitions API SPA + MPA

View Transitions API 让浏览器自动处理旧→新状态的快照、动画和清理,开发者只需声明"何时过渡"和"如何动画"。


SPA 中的 View Transitions

基本用法:document.startViewTransition

function navigateTo(newRoute: string) {
  if (!document.startViewTransition) {
    updateDOM(newRoute);
    return;
  }

  document.startViewTransition(() => {
    updateDOM(newRoute);
  });
}

浏览器自动执行:

  1. 截取旧状态快照(::view-transition-old
  2. 执行回调,更新 DOM
  3. 截取新状态快照(::view-transition-new
  4. 在两组快照之间执行交叉淡入淡出动画

自定义过渡动画

默认交叉淡入淡出

::view-transition-old(root) {
  animation: 0.3s ease-in both fade-out;
}
::view-transition-new(root) {
  animation: 0.3s ease-out both fade-in;
}

滑动切换效果

::view-transition-old(root) {
  animation: 0.4s ease-in both slide-to-left;
}
::view-transition-new(root) {
  animation: 0.4s ease-out both slide-from-right;
}

@keyframes slide-to-left {
  to { transform: translateX(-100%); }
}
@keyframes slide-from-right {
  from { transform: translateX(100%); }
}

共享元素过渡:跨组件动画

给元素设置 view-transition-name,浏览器自动在旧→新位置间做 FLIP 动画:

.card-image {
  view-transition-name: card-img;
}
.card-title {
  view-transition-name: card-title;
}

实战:列表→详情页的 Hero 动画

function openDetail(cardId: string) {
  document.startViewTransition(() => {
    document.querySelector('.list-page')!.style.display = 'none';
    document.querySelector('.detail-page')!.style.display = 'block';

    // 设置共享元素名称
    document.querySelector(`#card-${cardId} img`)!
      .style.viewTransitionName = 'hero-image';
    document.querySelector('.detail-hero img')!
      .style.viewTransitionName = 'hero-image';
  });
}

列表卡片图片 → 详情页大图之间自动做平滑缩放+位移动画。


MPA 跨文档过渡

Chrome 111+ 支持跨文档(跨页面导航)的 View Transitions:

启用跨文档过渡

<meta name="view-transition" content="same-origin">

只需一行 meta 标签,同源导航自动触发交叉淡入淡出!

配合 CSS 自定义

/* 仅在前进导航时滑动 */
::view-transition-old(root) {
  animation: 0.25s ease-in both slide-to-left;
}
::view-transition-new(root) {
  animation: 0.25s ease-out both slide-from-right;
}

/* 后退导航反向滑动 */
::view-transition-old(root) {
  animation: 0.25s ease-in both slide-to-right;
}
::view-transition-new(root) {
  animation: 0.25s ease-out both slide-from-left;
}

使用 Navigation Type 区分方向

@media (navigation: forward) {
  ::view-transition-old(root) { animation: slide-to-left; }
  ::view-transition-new(root) { animation: slide-from-right; }
}
@media (navigation: back) {
  ::view-transition-old(root) { animation: slide-to-right; }
  ::view-transition-new(root) { animation: slide-from-left; }
}

高级技巧

排除不需要动画的元素

/* 固定头部和底部不参与过渡 */
header, footer {
  view-transition-name: none;
}

动态设置 view-transition-name

// 列表中每张卡片有唯一名称
document.querySelectorAll('.card').forEach((card, i) => {
  card.style.viewTransitionName = `card-${i}`;
});

等待图片加载后再过渡

document.startViewTransition(async () => {
  updateDOM(newRoute);
  await document.querySelector('.detail-hero img')?.decode();
});

与工具库的结合


性能考量

方面 建议
快照大小 避免对大尺寸元素设置 view-transition-name
过渡时长 200-400ms 是感知最佳区间
并发过渡 多个共享元素同时动画时 GPU 负载增加
布局抖动 回调中避免触发布局重排,否则快照不准确

常见问题

startViewTransition 回调中可以异步更新 DOM 吗?

可以。回调支持 async 函数,浏览器会等待 Promise resolve 后再截取新快照。但等待期间旧快照一直显示,过长的等待会导致卡顿感。

跨文档过渡和 SPA 过渡的区别?

SPA 用 document.startViewTransition() 手动触发,MPA 用 <meta name="view-transition"> 自动触发。两者共享同一套 CSS 伪元素和动画定义。

如何调试 View Transitions?

Chrome DevTools → Elements 面板可查看 ::view-transition-group 等伪元素树。Animation 面板可逐帧调试过渡动画。


总结

View Transitions API 将页面过渡从手动 FLIP 计算变为浏览器原生快照+动画,大幅降低实现复杂度。SPA 用 document.startViewTransition(),MPA 用 meta 标签,共享元素用 view-transition-name——三种场景统一在同一套 CSS 伪元素体系下,是现代 Web 应用页面过渡的最佳方案。

本站提供浏览器本地工具,免注册即可试用 →

#View Transitions#页面过渡#MPA#SPA#跨文档动画