← ✦ UX 交互模式 · 那些有名字的交互细节 / View Transitions:让同一个元素在两个状态间「长」过去 待审核 7 / 7
view-transition · 共享元素转场

View Transitions:让同一个元素在两个状态间「长」过去

从一个缩略图点进详情页,如果界面硬切,用户得在新画面里重新找回「我刚点的是哪个」。共享元素转场 (Shared Element Transition) 的思路:告诉浏览器前后两个状态里哪个元素是同一个,剩下的位移 + 缩放中间帧由它自动补出——缩略图会平滑地长成大图,视线被这条连续的运动一路带过去。原生 document.startViewTransition() 让这件事不再需要手写动画。下面对比开 / 关转场。

机制只有两步:给缩略图和详情大图的同一元素标上相同的 view-transition-name;把切换 DOM 的操作包进 startViewTransition(callback)。浏览器会在回调前后截一张图,对同名元素自动生成 transform + clip 的补间,其余内容默认做交叉淡入淡出。整个过程不写一行 keyframes,且可被 ::view-transition-group() 进一步定制时长与缓动。

两步:命名 + 包住 DOM 更新——浏览器补出中间帧:

/* 1. 给前后两个状态的"同一元素"标同名 */
.thumb, .hero { view-transition-name: active-media; }

// 2. 把切换 DOM 的操作包进 startViewTransition
function openDetail(item) {
  if (!document.startViewTransition) return render(item); // 降级
  document.startViewTransition(() => render(item));        // 自动补间
}

1 · 跨文档转场:连真正的页面跳转也能补间

上面是同文档转场——DOM 没换、URL 没变,只是 JS 改了一段节点。但 View Transitions 真正打开局面的是跨文档(MPA):从一个 HTML 页面真的导航到另一个,中间也能补出连续动画。而且它一行 JS 都不用——只要导航的前后两个文档同源、且各自都写上这条 at-rule:

/* page-a.html 和 page-b.html 都写这一行 —— 同源即可 */
@view-transition { navigation: auto; }

/* 想让某个元素跨页"长"过去,就在两页给它同一个名字 */
.thumb { view-transition-name: vt-hero; } /* Page A 的小图 */
.hero  { view-transition-name: vt-hero; } /* Page B 的大图 */

下面这个内嵌站点有两个真实页面(相册 ↔ 详情),都开了 @view-transition。点「查看详情 / 返回」是 iframe 内一次真正的跨文档导航(URL 真的变了),那块封面会从小图位置长成大图——靠的是两页同名的 view-transition-name: vt-hero。右上角切换「默认 crossfade」与「圆形 clip-path 擦除」两种整页效果:

转场期间浏览器把页面快照拆成一棵伪元素树:每个 view-transition-name 各占一个 group,旧、新两帧叠在 image-pair 里交叉淡入淡出。想定制哪段动画(时长、缓动、上面的 clip-path 擦除),就用 @keyframes 命中对应伪元素:

用 @keyframes 把整页 crossfade 换成圆形擦除:

::view-transition-old(root) { animation: none; }   /* 旧页定住当背景 */
::view-transition-new(root) {                       /* 新页圆形扩开盖上来 */
  animation: 600ms vt-reveal cubic-bezier(.2, .6, .2, 1);
}
@keyframes vt-reveal {
  from { clip-path: circle(0%   at 50% 80%); }
  to   { clip-path: circle(150% at 50% 80%); }
}

三个约束: 其一,同一时刻一个 view-transition-name 只能属于一个可见元素(否则报错,本页用「隐藏另一侧」规避);其二,startViewTransition 截的是整页快照,转场期间页面短暂不可交互;其三,它对应本系列「用运动替代跳变」的主题,但动效要克制——并尊重 prefers-reduced-motion(浏览器会自动跳过)。