多页应用(MPA)和静态网站的视图转换 API 已准备好在 Chrome 113+ 中面进行测试 (通过 flags 开启)。MPA 的视图转换是我的 CSS 愿望清单上的一项重要功能。我花了不到一个小时的时间,零JavaScript 和两行CSS 实现。我对结果很满意。

⚠️ 在撰写本文时,这仅在 Chrome Canary 115 +中运行良好。我无法在其他浏览器中为您解决此问题。对于默认情况下未启用多页视图转换的浏览器(实际上是所有浏览器),您的页面将像普通页面一样加载。这种技术是一种✨奇妙的渐进式增强。

让我们开始将视图过渡添加到我们的网站...

1. 在 Chrome Canary 中启用标志

要开始使用视图过渡功能,请在 Chrome Canary 中启用视图过渡功能。

chrome://flags#view-transition
chrome://flags#view-transition-on-navigation

⚠️ 这些标志也存在于Chrome Stable和Arc中(但不是Edge?),但页面会随机锁定,所以坚持使用 Canary 或直到Chrome Stable在2023年7月12日左右达到 v115。尚未宣布他们何时/是否会在未来版本中取消标记此功能。

现在我们进入有趣的部分...

2. 包含视图过渡 meta 标记

将以下内容添加到布局模板的全局 <head>

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

恭喜,您现在有了页面过渡!此单行代码在整个站点上应用交叉淡入淡出效果。您的网站现在是一个PowerPoint。我不清楚标签 <meta> 是否是启用此功能的最终解决方案,但我很高兴看到它有效。

3. 添加单个元素过渡

您可能会问自己两个问题:

  • 如何创建比交叉淡入淡出更令人兴奋的效果?
  • 如何转换特定元素?

答案是:CSS 中的命名视图转换。为从 page1.html 转换的元素和要转换到 page2.html 的元素指定相同的唯一 view-transition-name。让我们以 Bootstrap 风格的“Jumbotron”为例。

<div class="jumbotron" style="view-transition-name: hero">
  <!-- content goes here -->
	<a href="/product.html">Buy Now</a>
</div>

找到 product.html 您希望元素变形的目标元素并为其提供相同的 view-transition-name 内容

<div class="product-header" style="view-transition-name: hero">
  <!-- content goes here -->
</div>

瞧!这在两个页面之间为您提供了“变形”效果。如果您讨厌内联样式,也可以在 CSS 文件中完成此操作。

.jumbotron { view-transition-name: hero }
.product-header { view-transition-name: hero }

如果你想成为一个真正的冠军,请为晕车的人禁用变形效果。🏆

@media not (prefers-reduced-motion: reduce) {
	.jumbotron { view-transition-name: hero }
	.product-header { view-transition-name: hero }
}

在开始进行我们自己的自定义转换之前,让我们暂停一分钟,看看这一切是如何工作的,并了解底层技术中的任何限制......

这一切是如何运作的?

在幕后,浏览器栅格化您正在转换的 DOM 元素的前后状态。浏览器找出这两个快照之间的差异,以及它们之间的补间,类似于Apple Keynote的“Magic Morph”功能,《终结者2:审判日》中的液态金属T-1000,或1980年代的卡通系列Turbo Teen。

Title series for the 80s animated cartoon series Turbo Teen featuring a boy turning into a hot rod car

如果这些参考资料在你身上丢失了,那么流行的儿童读物系列Animorphs怎么样?

animorphs book cover of a boy slowly fading into a tiger

这正是它的工作原理,不,我不会回答任何进一步的问题。有趣的是,它似乎协商了 X,Y 位置以及前后状态的高度/宽度。然后,它将热交换光栅化图像(如过渡)的 DOM,调整大小转换高度/宽度,平移位置,并在旧状态和新状态之间交叉淡入淡出动画。基本但令人信服。

包含许多项目的列表的独特限制

现在,MPA 视图转换需要是唯一的!如果同一页面上有两个具有相同过渡名称的元素(例如), view-transition-name: post 浏览器会感到困惑,并将在视图过渡时放弃,回退到交叉淡入淡出。

值得庆幸的是,如果您尝试通过在模板中添加唯一 view-transition-name 视图来从列表视图到详细信息视图再返回动画,则有一个解决方法。此示例是帖子列表:

<div class="posts">
{% foreach post in posts %}
  <a style="view-transition-name: post-{{ post.id }}" href="{{ post.url }}">{{ post.title }}</a>
{% endforeach %}
</div>

此视图过渡将在呈现的 HTML 中具有 的名称 post-123 。然后,您将相同的“slug”添加到帖子模板中,以将链接变形为文章标题。

<article>
  <header style="view-transition-name: post-{{ post.id }}">
    <h1>{{ post.title }}</h1>
  </header>
  ...
</article>

现在,您已经入侵了系统,并且能够按预期进行转换。需要注意的一个副作用是,这会在 Web 检查器中创建大量伪元素...

<!DOCTYPE html>
<html lang="en-us">
  ::view-transition-group(root)
  ::view-transition-group(post-123)
  ::view-transition-group(post-124)
  ... etc
	::view-transition-image-pair(root)
	::view-transition-image-pair(post-123)
	::view-transition-image-pair(post-124)
	... etc
	::view-transition-old(root)
	::view-transition-old(post-123)
	::view-transition-old(post-124)
  ... etc
	::view-transition-new(root)
	::view-transition-new(post-123)
	::view-transition-new(post-124)
	... etc

我想这是相当没有意义的,但也可能类似于“太多 DOM 节点”的性能和调试问题。你做你想做的事,但我可能会对此持保守态度,避免将其应用于巨大的列表。我希望出现一个更好的、更少的手动/显式 API,用于从列表到细节的转换,但现在这是有效的。

4. 自定义视图过渡

如果“变形”过渡不是您想要的怎么办?您可以使用 和 伪元素控制命名视图过渡的旧(传出)状态 ::view-transition-old()::view-transition-new() 新(传入)状态。

/* Old stuff going out */
::view-transition-old(hero) {
  animation: fade 0.2s linear forwards;
}

/* New stuff coming in */
::view-transition-new(hero) {
  animation: fade 0.3s linear reverse;
}

@keyframes fade {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

这有点重复,但控制传入和传出内容很好。一些细微的调整,例如使旧内容淡出的速度比新内容快一点,可以使你的应用感觉独一无二。

我主要使用默认的变形过渡,但在我的“关于”部分子导航中遇到了一个问题,由于页面之间的内容容器大小不同,我不喜欢变形过渡如何缩放我的文本。添加到 width: fit-content 过渡效果很好,我得到了我想要很长时间的快速水平调整大小效果。

天空是你想走多远的极限。准备好迎接您附近网站的令人震惊的动画划像。

玩得开心,循序渐进

我认为多页视图转换 API 成功的最有说服力的预测指标 - 与之前的所有其他提案和解决方案相比 - 是我实际实现了这个。尽管动画多年来一直是我的面包和黄油,但我甚至无法尝试任何上一代工具。

使用 <meta> 标签和少量CSS属性轻松创建高质量的60 FPS页面过渡的能力改变了游戏规则,我期待着更有创造力的人会用这项技术做什么。我的脑袋里已经充满了想法。关于MPA视图过渡的最好的部分是,在引擎盖下,它只是正常的“愚蠢”页面加载,我们正在逐步增强我们进入智能,时尚过渡的方式,所有这些都不需要JavaScript。

我当然希望其他浏览器加入。👀