网页的一种常见模式是使用 JavaScript 动态替换网页上的内容,而无需加载新的完整 HTML 文档。这称为单页应用 (SPA)。视图过渡功能可让您在 SPA 中的网页之间显示连续性或上下文。
全屏过渡
当用户在 SPA 中导航到新视图时,框架会使用新内容替换 DOM。这样一来,内容就会直接显示,但如果您想在当前内容和新内容之间提供过渡效果,该怎么办?
过渡效果通常会同时显示旧视图和新视图,例如淡出旧视图,同时淡入新视图。由于现有内容会被替换,因此在视图过渡之前,这是一个难题。
如需使用视图过渡,您需要将用于更改 DOM 的逻辑封装在回调中。在这些示例中,我们通过名为 MyRouter
的 Web 组件提供了一个基本路由器实现。启用视图过渡的方式取决于您使用的路由器和框架。
document.startViewTransition(() => updateTheDOMSomehow());
这会启用默认过渡效果,即旧视图淡出,同时新视图淡入。
这里发生了什么?当您调用 document.startViewTransition()
时,浏览器会拍摄旧视图的快照。然后,它会调用您传递的回调函数,该函数会将 DOM 更新为新视图(但尚未显示)。回调函数完成后,浏览器会开始过渡到新内容。
// Fallback for browsers that don't support this API:
if (!document.startViewTransition) {
updateTheDOMSomehow();
return;
} else {
// With a View Transition:
document.startViewTransition(() => updateTheDOMSomehow());
}
自定义过渡效果
如您在前面的示例中所见,默认的视图过渡效果是淡出旧视图,同时淡入新视图。您可以通过设置由视图转换生成的伪元素的样式,自定义过渡效果,使其更符合网站的风格。
您可以使用 ::view-transition-old()
指定离开过渡效果,并使用 ::view-transition-new()
指定进入过渡效果。您还可以使用 ::view-transition-group()
同时指定这两个值。
在此示例中,旧视图将使用 slide-out-to-left
过渡效果淡出,新视图将使用 slide-in-from-right
过渡效果淡入。两者的时长均为 200 毫秒。
::view-transition-group(root){
animation-duration: 200ms;
}
::view-transition-old(root) {
animation-name: slide-out-to-left;
}
::view-transition-new(root) {
animation-name: slide-in-from-right;
}
根据情景采用不同的过渡效果
您可能希望根据用户正在执行的操作来设置不同的过渡效果。例如,如果点击首页上的链接会使新视图从右侧滑入,那么您会预期点击链接返回首页时,首页视图会从左侧滑入。
您可以使用 :active-view-transition-type()
伪类指定不同的动画。
html:active-view-transition-type(forwards) {
&::view-transition-old(root) {
animation-name: slide-out-to-left;
}
&::view-transition-new(root) {
animation-name: slide-in-from-right;
}
}
然后,您可以选择在调用 document.startViewTransition()
时使用哪种视图过渡类型。
const direction = next === 'home' ? 'backwards' : 'forwards';
document.startViewTransition({
update: updateTheDOMSomehow,
types: [direction],
});
过渡特定元素
到目前为止,您只将过渡效果应用于根元素,以过渡整个视图。不过,您也可以使用视图过渡为网页的特定部分添加动画效果。
例如,旧视图中的内容可能与新视图中的内容相匹配。可以是内容标题或图片。旧视图中甚至可以是缩略图,而新视图中是视频。
首先,您需要使用 view-transition-name
属性指定要过渡的元素。为了使视图转换正常运行,对于每个 view-transition-name
,在调用 document.startViewTransition()
之前需要恰好有一个元素,并且在 document.startViewTransition()
中的回调完成之后也需要恰好有一个元素。
在此示例中,音乐播放器会显示专辑封面、标题和音乐人。另一种视图显示的是重新排列的相同内容,并添加了歌词。
在上面的示例中,旧视图和新视图中各有且仅有一个过渡元素,并且它们甚至共享相同的选择器。过渡元素看起来会在其大小和位置之间移动。视图中未发生过渡的部分会淡入和淡出。
我们来看一个更复杂的示例。例如,博客首页可能会显示每篇博文的标题和图片,这些内容也会显示在博文的完整网页视图中。在从首页导航到特定帖子时,您可能希望让标题和图片看起来像是过渡到新位置,以提供上下文。
若要为标题执行此操作,您需要在旧视图中的标题元素上设置一个唯一的 view-transition-name
,该 view-transition-name
与新视图中的标题元素共享,并且在新视图中是唯一的。这是一个难题,因为首页包含多个标题和图片,您不知道用户会点击哪个。
您可以通过两种方式解决此问题。您可以选择为首页上的每篇帖子添加唯一的 view-transition-name
,然后在每篇完整版帖子中匹配该名称。您可以使用帖子的 ID 生成这些内容。另一种选择是使用通用 view-transition-name
,但仅在用户点击帖子后、调用 document.startViewTransition()
之前应用。
设计过渡
视图过渡是一组工具,可用于引导用户并提供额外的品牌或上下文提示。您可能会使用多种技术来找到适合您网站的过渡效果。
根据您想要的效果,您可能还需要调整元素或动画。在前面的示例中,我们调整了多种样式,以实现平滑的过渡效果。
标题具有规则 width: fit-content
,当您转换不换行的文字(或在旧视图和新视图中具有相同的换行)时,这是一种有用的样式。否则,过渡可能发生在宽度不同的元素之间,这会使过渡效果不够平滑。
此外,图片在旧视图和新视图中的宽高比也不同。此示例修改了动画和 object-fit
属性,使过渡看起来很平滑。
尊重 prefers-reduced-motion
用户请求减少动态效果的一个常见原因是,全屏动画(例如通过视图过渡实现的全屏动画)可能会让患有平衡障碍的人感到不适。您可以使用 prefers-reduced-motion
媒体查询停用动画。您还可以选择提供更细致的替代动画,但仍能传达元素之间的关联。
@media (prefers-reduced-motion) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
}
}
检验您的掌握情况
表示调用 document.startViewTransition()
之前的视图的伪元素的名称是什么?
::view-transition-previous
::view-transition-prior
::view-transition-old
::view-transition-initial
视图过渡的默认动画是什么?
网页的默认 view-transition-name
是什么?
document
shadow-root
root
body