CSS 视图转换模块 第 1 级

W3C 候选推荐快照,

更多关于本文件的详情
此版本:
https://www.w3.org/TR/2024/CRD-css-view-transitions-1-20240328/
最新发布版本:
https://www.w3.org/TR/css-view-transitions-1/
编辑草案:
https://drafts.csswg.org/css-view-transitions-1/
历史记录:
https://www.w3.org/standards/history/css-view-transitions-1/
实施报告:
https://wpt.fyi/results/css/css-view-transitions
反馈:
CSSWG 问题仓库
编辑:
Tab Atkins-Bittner (Google)
Jake Archibald (Google)
Khushal Sagar (Google)
建议对本规范进行编辑:
GitHub 编辑器

摘要

本模块定义了视图转换 API 及其相关属性和伪元素,允许开发人员创建反映文档状态变化的动画视觉转换。

CSS 是一种用于描述结构化文档(如 HTML 和 XML)在屏幕、纸张等上的渲染的语言。

本文档的状态

本节描述了本文档在发布时的状态。当前 W3C 出版物列表及本技术报告的最新版本可在 W3C 技术报告索引 https://www.w3.org/TR/ 查询。

本文档由CSS 工作组作为候选推荐草案(Candidate Recommendation Draft)推荐标准路径上发布。 作为候选推荐草案发布,并不意味着 W3C 及其成员的认可。 候选推荐草案整合了工作组打算纳入后续候选推荐快照的前一版候选推荐中的更改。

本文档为草案,可能随时被更新、替换或废弃。除非作为工作进展,不应引用此文档。

请通过在 GitHub 提交 issue(优先推荐)反馈意见,标题中请包含规范代码 “css-view-transitions”,格式如下:“[css-view-transitions] ……意见摘要……”。所有问题和评论均已归档。 或可通过(归档)公共邮件列表 www-style@w3.org 反馈。

本文档受 2023年11月3日 W3C 流程文档 规范管理。

本文档由遵循 W3C 专利政策 的小组制作。W3C 维护着一份与本组交付物相关的公开专利披露列表;该页面还包含披露专利的说明。任何知晓包含必要权利要求的专利的个人,必须按照W3C 专利政策第6节的要求进行披露。

1. 简介

本节是非规范性的。

本规范引入了一个 DOM API 和相关的 CSS 功能, 使开发者可以创建称为 视图过渡 的动画视觉过渡, 用于不同 文档 状态之间的切换。

1.1. 将视觉过渡与 DOM 更新分离

传统上,在两个文档状态之间创建视觉过渡需要一个阶段,在该阶段两个状态同时存在于 DOM 中。 实际上,通常需要创建一个特定的 DOM 结构来表示这两个状态。 例如,如果一个元素在容器之间“移动”,则该元素通常需要在过渡期间存在于两个容器之外, 以避免被任一容器或它们的祖先元素裁剪。

这种额外的中间状态常常导致用户体验和可访问性问题,因为 DOM 的结构被纯粹的视觉效果所破坏。

视图过渡避免了这种麻烦的中间状态, 通过允许 DOM 即时切换状态, 然后在另一个层次上执行两种状态之间的可定制视觉过渡, 使用旧状态的静态视觉捕获和新状态的实时捕获。 这些捕获表示为 伪元素 的树(详细信息见 § 3.2 视图过渡伪元素), 其中旧的视觉状态与新的状态共存,允许如淡入淡出等效果, 同时从旧的大小和位置动画到新的大小和位置。

1.2. 视图过渡定制化

默认情况下, document.startViewTransition() 创建一个页面范围内的淡入淡出过渡, 在两个 DOM 状态之间。 开发者也可以选择独立捕获某些元素, 使用 view-transition-name CSS 属性, 使这些元素可以独立于页面的其他部分进行动画。 由于过渡状态(旧的和新的视觉捕获同时存在)表示为伪元素, 开发者可以使用诸如 CSS 动画Web 动画 等熟悉的功能来自定义每个过渡。

1.3. 视图过渡生命周期

成功的 视图过渡 经过以下阶段:

  1. 开发者调用 document.startViewTransition(updateCallback), 该方法返回一个 ViewTransition 对象 viewTransition

  2. 当前状态被捕获为“旧”状态。

  3. 渲染被暂停。

  4. 开发者提供的 updateCallback 回调函数(如果有)被调用,从而更新文档状态。

  5. viewTransition.updateCallbackDone 得到 fulfill。

  6. 当前状态被捕获为“新”状态。

  7. 创建过渡伪元素。参见 § 3.2 视图过渡伪元素 了解该结构概述。

  8. 渲染恢复,显示过渡伪元素。

  9. viewTransition.ready 得到 fulfill。

  10. 伪元素持续动画直至结束。

  11. 移除过渡伪元素。

  12. viewTransition.finished 得到 fulfill。

1.4. 过渡作为增强功能

视图过渡 API 设计的一个关键部分 是动画过渡是对底层文档状态变化的视觉增强。 这意味着,即使由于配置错误或设备限制导致无法创建视觉过渡, 也不会阻止开发者的 UpdateCallback 被调用, 即使事先已知过渡动画无法发生。

例如,如果开发者在 视图过渡生命周期 开始时调用 skipTransition(), 则与动画过渡相关的步骤, 如创建 视图过渡树, 将不会发生。 然而,UpdateCallback 仍然会被调用。 仅跳过了视觉过渡,而不是底层的状态变化。

注意:如果还希望跳过 DOM 更改,则需要通过其他功能来处理。 navigateEvent.signal 是开发者可以用来处理此情况的一个功能示例。

尽管视图过渡 API 允许通过 UpdateCallback 使 DOM 更改异步进行, 该 API 并不负责排队或以其他方式调度 DOM 更改, 除了任何过渡本身所需的调度外。 一些异步 DOM 更改可以同时发生(例如,它们发生在独立的组件中), 而另一些则需要排队或中止先前的更改。 最好将这些留给对应用程序有更全面了解的功能或框架来处理。

1.5. 渲染模型

视图过渡通过使用用户代理生成的伪元素来复制元素的渲染状态。 应用于元素自身或其后代的渲染方面, 例如视觉效果如 filteropacity, 以及来自 overflowclip-path 的裁剪, 在 捕获图像 时应用。

然而,诸如 mix-blend-mode 之类定义了元素嵌入时如何绘制的属性,无法应用于其图像。 这些属性被应用于元素的对应 ::view-transition-group() 伪元素, 该伪元素旨在生成一个等同于元素的盒子。

如果 ::view-transition-group() 在“新”状态中有对应的元素, 浏览器将保持复制到 ::view-transition-group() 的属性与“新”状态的 DOM 元素同步。 如果 ::view-transition-group() 在“旧”状态和“新”状态中都有对应, 并且被复制的属性是可插值的, 浏览器还会设置一个默认动画来平滑地对该属性进行动画处理。

1.6. 示例

假设有一个页面已经使用如下模式更新内容:
function spaNavigate(data) {
  updateTheDOMSomehow(data);
}

可以如下为其添加视图过渡(view transition)

function spaNavigate(data) {
  // 针对不支持该 API 的浏览器的降级处理:
  if (!document.startViewTransition) {
    updateTheDOMSomehow(data);
    return;
  }

  // 带有过渡效果:
  document.startViewTransition(() => updateTheDOMSomehow(data));
}

这样会产生默认的快速渐变过渡效果:

渐变过渡是通过 CSS 动画作用在伪元素树上实现的,因此可以使用 CSS 进行自定义。例如:

::view-transition-old(root),
::view-transition-new(root) {
	animation-duration: 5s;
}

这会使过渡变得更慢:

基于上一个示例,可以添加动画效果:
@keyframes fade-in {
	from { opacity: 0; }
}

@keyframes fade-out {
	to { opacity: 0; }
}

@keyframes slide-from-right {
	from { transform: translateX(30px); }
}

@keyframes slide-to-left {
	to { transform: translateX(-30px); }
}

::view-transition-old(root) {
	animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
		300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
}

::view-transition-new(root) {
	animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,
		300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
}

这是效果:

基于上一个示例, 可以为标题和标题内的文本分别设置自己的::view-transition-group()以进行过渡:
.main-header {
	view-transition-name: main-header;
}

.main-header-text {
	view-transition-name: main-header-text;
	/* 为元素赋予一致的大小,假设文本相同:*/
	width: fit-content;
}

默认情况下,这些组将从“旧”状态过渡到“新”状态时改变大小和位置,同时视觉状态进行交叉淡化:

基于上一个示例,假设有些页面有一个侧边栏:

在这种情况下,如果“旧”和“新”状态中都有侧边栏,静态展示会更好。否则,它应该以动画形式进入或退出。

:only-child伪类可以专门为这些状态创建动画:

.sidebar {
	view-transition-name: sidebar;
}

@keyframes slide-to-right {
	to { transform: translateX(30px); }
}

/* Entry transition */
::view-transition-new(sidebar):only-child {
	animation: 300ms cubic-bezier(0, 0, 0.2, 1) both fade-in,
		300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
}

/* Exit transition */
::view-transition-old(sidebar):only-child {
	animation: 150ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
		300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-right;
}

For cases where the sidebar has both an “old” and “new” state, the default animation is correct.

这次不基于之前的示例, 假设我们想从用户的光标位置创建一个圆形显示效果。 这无法仅靠 CSS 完成。

首先,在 CSS 中允许“旧”和“新”状态叠加在一起而不进行默认的混合,防止默认的交叉淡化动画:

// 存储上一次点击事件
let lastClick;
addEventListener('click', event => (lastClick = event));

function spaNavigate(data) {
  // 针对不支持该 API 的浏览器的降级处理:
  if (!document.startViewTransition) {
    updateTheDOMSomehow(data);
    return;
  }

  // 获取点击位置,若无则取屏幕中心
  const x = lastClick?.clientX ?? innerWidth / 2;
  const y = lastClick?.clientY ?? innerHeight / 2;
  // 计算到最远角的距离
  const endRadius = Math.hypot(
    Math.max(x, innerWidth - x),
    Math.max(y, innerHeight - y)
  );

  // 创建视图过渡:
  const transition = document.startViewTransition(() => {
    updateTheDOMSomehow(data);
  });

  // 等待伪元素创建完毕:
  transition.ready.then(() => {
    // 动画 root 的新视图
    document.documentElement.animate(
      {
        clipPath: [
          `circle(0 at ${x}px ${y}px)`,
          `circle(${endRadius}px at ${x}px ${y}px)`,
        ],
      },
      {
        duration: 500,
        easing: 'ease-in',
        // 指定要动画的伪元素
        pseudoElement: '::view-transition-new(root)',
      }
    );
  });
}

结果如下:

2. CSS 属性

2.1. 为独立过渡的子树标记:view-transition-name 属性

名称: view-transition-name
值: none | <custom-ident>
初始值: none
适用于: 所有元素
是否继承: no
百分比: n/a
计算值: 按指定
规范顺序: 符合语法
动画类型: 离散

注意:虽然 view-transition-name离散可动画(discretely animatable)的, 但对其进行动画并不会影响正在运行的视图过渡(view transition)。相反,这是一种可以随时间或基于时间线(timeline)变化的方式来设置其值的手段。 一个使用场景示例是根据滚动驱动动画(scroll-driven animations)来更改 view-transition-name

view-transition-name 属性用于将元素“标记”为在视图过渡中捕获,并在指定的视图过渡名称(view transition name)下,于视图过渡树(view transition tree)中独立跟踪。被这样捕获的元素会独立于页面其他部分进行动画。

none

元素不会以独立方式参与视图过渡。

<custom-ident>

元素将以独立方式参与视图过渡——作为“旧”或“新”元素——并使用指定的视图过渡名称

这里的 noneauto 两个值不属于 <custom-ident> 的范畴。

注意:如果此名称不是唯一的(即有两个元素同时指定了相同的 view transition name),那么该视图过渡将会中止。

注意:对于此 API, 如果某元素在旧状态下具有 view transition name foo, 而另一个元素在新状态下也具有 view transition name foo, 它们会被视为同一元素的不同可视状态,并在视图过渡树中配对。虽然这些元素本身未必指向同一对象,但将其视为同一概念页面实体的不同视觉状态是有用的模型。

如果元素的主盒(principal box)分片(fragmented)跳过内容(skipped), 或未渲染(not rendered),则该属性不会生效。 具体细节参见 § 7 算法

2.1.1. 渲染合并

元素视图过渡期间被捕获, 或者其 view-transition-name计算值不是 none(在任何时间):

3. 伪元素

3.1. 伪元素树

注意:这是伪元素树的通用定义。如果其他特性需要此行为,这些定义将移至 [css-pseudo-4]

伪元素根是一种 树状伪元素, 它是中的 , 这种树被称为伪元素树

伪元素树定义了其 后代 树状伪元素的文档顺序。

当一个伪元素 参与 一个伪元素树时, 它的原始伪元素是它的 父元素

如果伪元素根 的一个后代 pseudo 没有其他兄弟元素, 那么:only-child 匹配该 pseudo

注意:这意味着 ::view-transition-new(ident):only-child 仅在父元素 ::view-transition-image-pair(ident) 中 包含一个子元素时选择它。 也就是说,没有其他兄弟元素 ::view-transition-old(ident)

3.2. 视图过渡伪元素

视图过渡的可视化表示为一个称为 伪元素树的结构, 称为视图过渡树, 由下面定义的视图过渡伪元素组成。 这个树在设置过渡伪元素步骤期间构建, 并在从::view-transition伪元素 起源根元素。 所有的视图过渡伪元素都是从它们的 最终起源元素中选取, 即文档元素

视图过渡树(view transition tree)不会暴露给可访问性树(accessibility tree)。

例如, ::view-transition-group() 伪元素直接附加到根元素选择器上, 就像:root::view-transition-group()那样; 它不附加到其父元素::view-transition伪元素。
一旦用户代理捕获了文档的“旧”和“新”状态, 它就会创建一个如下所示的伪元素结构:
::view-transition
├─ ::view-transition-group(name)
│  └─ ::view-transition-image-pair(name)
│     ├─ ::view-transition-old(name)
│     └─ ::view-transition-new(name)
└─ …其他组…

每个带有 view-transition-name 的元素都会被单独捕获,并且每个唯一的 view-transition-name 都会生成一个 ::view-transition-group()

为了方便起见,文档元素(document element)用户代理样式表(user-agent style sheet) 中被赋予 view-transition-name 值为 "root"。

如果某次捕获没有“旧”或“新”状态,则 ::view-transition-old()::view-transition-new() 会缺失。

生成的每个伪元素都可以通过 CSS 进行定向,从而自定义其外观、行为和/或添加动画。这使得过渡效果可以实现完全的自定义。

3.2.1. 命名视图过渡伪元素

一些视图过渡伪元素命名视图过渡伪元素, 它们是函数式 树状 视图过渡伪元素,与视图过渡名称相关联。 这些伪元素以<pt-name-selector>作为参数, 其语法遵循以下模式:

::view-transition-pseudo(<pt-name-selector>)

其中<pt-name-selector>选择一个 视图过渡名称, 其语法定义如下:

<pt-name-selector> = '*' | <custom-ident>

命名视图过渡伪元素 选择器仅在其 <pt-name-selector> 匹配相应的伪元素伪元素视图过渡名称时匹配, 也就是说,如果它是*或匹配的 <custom-ident>

注意: 视图过渡伪元素视图过渡名称设置为触发其创建的 view-transition-name

命名视图过渡伪元素 选择器<custom-ident>参数 的优先级等同于类型选择器命名视图过渡伪元素选择器带有 *参数的优先级为零。

3.2.2. 视图过渡树根:::view-transition伪元素

::view-transition 伪元素 是一个树状伪元素, 同时也是一个伪元素根。 它的起源元素 是文档的文档元素, 它的包含块快照包含块

注意:这个元素作为所有::view-transition-group()伪元素的父元素

3.2.3. 视图过渡命名子树根:::view-transition-group()伪元素

::view-transition-group() 伪元素 是一个命名视图过渡伪元素, 表示匹配的命名视图过渡捕获。 每个视图过渡名称都会生成一个 ::view-transition-group() 伪元素,作为子元素, 附加到::view-transition 伪元素上,并包含一个相应的::view-transition-image-pair()

这个元素最初镜像“旧”元素的大小和位置,如果没有“旧”元素则是“新”元素。

如果同时存在“旧”和“新”状态, 动态视图过渡样式表中的样式 动画化此伪元素的宽度高度, 从旧元素的边框盒大小动画到新元素的 边框盒大小。

同时,元素的变换 从旧元素的屏幕空间变换动画到新元素的屏幕空间变换。

这些样式是动态生成的,因为动画属性的值是在过渡开始时确定的。

3.2.4. 视图过渡图像对隔离:::view-transition-image-pair()伪元素

::view-transition-image-pair() 伪元素 是一个命名视图过渡伪元素, 表示一对相应的“旧/新”视图过渡捕获。 这个伪元素是相应::view-transition-group()伪元素的 子元素, 并包含一个相应的::view-transition-old()伪元素 和/或一个相应的::view-transition-new()伪元素(按此顺序)。

该元素用于为其子元素提供隔离:isolate, 并且始终作为每个::view-transition-group()子元素。 这种隔离允许图像对以非正常混合模式进行混合,而不影响其他视觉输出。

3.2.5. 视图过渡旧状态图像:::view-transition-old()伪元素

::view-transition-old() 伪元素 是一个空的命名视图过渡伪元素, 表示“旧”状态的视觉快照,作为替换元素; 如果没有“旧”状态可表示,则省略。 每个::view-transition-old()伪元素 都是相应::view-transition-image-pair()伪元素的 子元素

:only-child可以用来匹配此元素是 ::view-transition-image-pair()中唯一元素的情况。

此元素的外观可以通过object-*属性进行操作,就像其他替换元素一样。

注意:图像的内容和自然尺寸捕获图像过程中被捕获, 并在设置过渡伪元素时设置。

注意:动态视图过渡样式表中添加的额外样式, 用于为这些伪元素添加动画,详细信息在设置过渡伪元素更新伪元素样式中描述。

3.2.6. 视图过渡新状态图像:::view-transition-new()伪元素

::view-transition-new() 伪元素 (类似于::view-transition-old()伪元素) 是一个空的命名视图过渡伪元素, 表示“新”状态的视觉快照,作为替换元素; 如果没有“新”状态可表示,则省略。 每个::view-transition-new()伪元素 都是相应::view-transition-image-pair()伪元素的 子元素

注意:图像的内容和自然尺寸捕获图像过程中被捕获, 然后在设置过渡伪元素更新伪元素样式中设置并更新。

4. 视图过渡布局

视图过渡伪元素的样式、布局和渲染方式类似于普通元素, 但它们起源于快照包含块, 而不是初始包含块, 并在文档其余部分之上的视图过渡层中绘制。

4.1. 快照包含块

快照包含块(snapshot containing block)是一个覆盖窗口所有可能显示页面内容区域的矩形(因此无论根滚动条或交互控件(interactive widgets)如何,都是一致的)。这通常也意味着它对于文档元素(document element)旧图像(old image)新元素(new element)来说是一致的。

对于 iframe,快照包含块对应其初始包含块(initial containing block)

A diagram of a phone screen, including a top status bar, a browser URL bar, web-content area with a floating scrollbar, a virtual keyboard, and a bottom bar with an OS back button The previous diagram, but highlights the area that's the 'snapshot containing block', which includes everything except the top status bar and the bottom bar with the OS back button
快照包含块(snapshot containing block) 在移动操作系统上的示例。
快照包含了 URL 栏(因为它可能被滚动隐藏),也包含了键盘(因为它会出现和消失)。
顶部和底部栏属于操作系统的一部分,而不是浏览器,所以它们不包含在快照包含块中。
A diagram of a desktop browser window, including a tab bar, a URL bar, and a web-content area featuring both horizontal and vertical scrollbars The previous diagram, but highlights the area that's the 'snapshot containing block', which includes the web content area and the scrollbars
快照包含块(snapshot containing block) 在桌面操作系统上的示例。
这里包括了滚动条,但不包括 URL 栏,因为网页内容不会出现在那个区域。

快照包含块原点(snapshot containing block origin) 指的是 快照包含块 的左上角。

快照包含块尺寸(snapshot containing block size) 指的是 快照包含块 的宽度和高度,用两个数字的元组(tuple)表示。

快照包含块 被视为 绝对定位包含块(absolute positioning containing block)固定定位包含块(fixed positioning containing block),适用于 ::view-transition 及其后代元素。

4.2. 视图过渡绘制顺序

本规范在CSS2 §E 叠层上下文的详细描述的绘制顺序末尾引入了一个新的叠层,称为 视图过渡层[CSS2]

::view-transition伪元素生成了一个新的叠层上下文, 称为视图过渡层, 它在文档的所有其他内容(包括在顶层中渲染的任何内容)之后绘制, 在应用于这些内容的所有滤镜和效果之后。 (它不受这些滤镜或效果的影响,除非它们影响 ::view-transition-old()::view-transition-new()伪元素的渲染内容)。

注意:此功能的目的是能够捕获页面内容,包括顶层元素。 为了实现这一点,视图过渡层不能成为捕获的叠层上下文的一部分, 因为这会导致循环依赖。 因此,视图过渡层是所有其他内容的兄弟元素。

当一个 Document激活视图过渡(active view transition)阶段(phase)为 "animating" 时, 该 Document 中 任何被视图过渡捕获的元素及其 元素内容(element contents)所生成的盒, 除了过渡根伪元素(transition root pseudo-element)包含后代(inclusive descendants)外, 都不会被绘制(就如同它们有 visibility: hidden)并且 不响应命中测试(就如同它们有 pointer-events: none)。

注意:参与过渡的元素需要在其 DOM 位置跳过绘制,因为它们的图像会被绘制到相应的 ::view-transition-new() 伪元素中。 同样,命中测试也会被跳过,因为元素的 DOM 位置不再对应其内容实际渲染的位置。 不过,这些元素通过辅助技术或可访问性树的访问方式不会发生变化。

5. 用户代理样式表

全局视图过渡用户代理样式表 是包含以下规则的用户代理来源样式表:

:root {
	view-transition-name: root;
}

:root::view-transition {
	position: fixed;
	inset: 0;
}

:root::view-transition-group(*) {
	position: absolute;
	top: 0;
	left: 0;

	animation-duration: 0.25s;
	animation-fill-mode: both;
}

:root::view-transition-image-pair(*) {
	position: absolute;
	inset: 0;

	animation-duration: inherit;
	animation-fill-mode: inherit;
    animation-delay: inherit;
}

:root::view-transition-old(*),
:root::view-transition-new(*) {
	position: absolute;
	inset-block-start: 0;
	inline-size: 100%;
	block-size: auto;

	animation-duration: inherit;
	animation-fill-mode: inherit;
    animation-delay: inherit;
}

/* 默认淡入淡出过渡动画 */ 
@keyframes -ua-view-transition-fade-out {
	to { opacity: 0; }
}
@keyframes -ua-view-transition-fade-in {
	from { opacity: 0; }
}

/* 当有两个图像时进行混合的关键帧动画 */ 
@keyframes -ua-mix-blend-mode-plus-lighter {
	from { mix-blend-mode: plus-lighter }
	to { mix-blend-mode: plus-lighter }
}
解释性摘要 此用户代理样式表执行了以下操作:

用户代理来源视图过渡期间, 通过动态视图过渡样式表 额外添加样式。

6. API

6.1. Document 的扩展

partial interface Document {
  ViewTransition startViewTransition(optional UpdateCallback updateCallback);
};

callback UpdateCallback = Promise<any> ();
viewTransition = document.startViewTransition(updateCallback)

启动一个新的视图过渡(如果存在,将取消document的现有活动视图过渡)。

updateCallback(如果提供的话)会在文档当前状态被捕获后异步调用。 随后,当 updateCallback 返回的 Promise 被解决时, 文档的新状态会被捕获,并且过渡(transition)会被发起。

请注意,updateCallback(如果提供)总是会被调用, 即使过渡无法发生(例如因为存在重复的 view-transition-name 值)。 过渡只是对状态变更的增强,因此过渡创建失败绝不会阻止状态的更改。 有关此原则的更多细节,请参见 § 1.4 作为增强的过渡(Transitions as an enhancement)

如果由updateCallback返回的Promise被拒绝,则跳过该过渡。

6.1.1. startViewTransition() 方法步骤

对于startViewTransition(updateCallback)方法步骤如下:
  1. transition当前对象(this)相关 Realm 中新建的 ViewTransition 对象。

  2. 如果提供了 updateCallback,则将 transitionupdate callback 设为 updateCallback

  3. document当前对象(this)相关全局对象(relevant global object)关联文档(associated document)

  4. 如果 documentvisibility state 为 "hidden",则用 "InvalidStateError" DOMException 跳过 transition,并返回 transition

  5. 如果 document激活视图过渡(active view transition) 不为 null,则用 "AbortError" DOMException当前对象(this)相关 Realm 跳过该视图过渡

    注意: 这可能导致两个异步 update callback 并发运行(因此可能无序):一个属于 document 当前的 激活视图过渡,另一个属于本次 transition。按照本特性的设计,假定开发者会用其它机制或框架正确调度这些 DOM 变更。

  6. document激活视图过渡 设置为 transition

    注意: 视图过渡的流程会在设置视图过渡(setup view transition),通过 执行待处理过渡操作(perform pending transition operations)继续进行。

  7. 返回 transition

6.2. ViewTransition 接口

[Exposed=Window]
interface ViewTransition {
  readonly attribute Promise<undefined> updateCallbackDone;
  readonly attribute Promise<undefined> ready;
  readonly attribute Promise<undefined> finished;
  undefined skipTransition();
};

ViewTransition 接口表示并控制一个同文档的视图过渡,即起始文档和结束文档相同,但可能会对文档的 DOM 结构进行更改。

viewTransition.updateCallbackDone

一个 Promise,当updateCallback返回的 Promise 解决时会被解决,当它被拒绝时则会被拒绝。

注意:视图过渡 API 封装了 DOM 更改并创建了视觉过渡。然而,有时你并不关心过渡动画的成功或失败,只想知道 DOM 何时发生变化。updateCallbackDone 适用于这种情况。)

viewTransition.ready

一个 Promise,一旦创建了过渡的伪元素,并且动画即将开始时会被解决。

如果无法开始过渡,则会被拒绝。这可能是由于配置错误,例如重复的 'view-transition-name',或者updateCallbackDone返回了一个被拒绝的 Promise。

ready解决的时刻是使用 Web Animation API 来为视图过渡伪元素添加动画的理想时机。

viewTransition.finished

一个 Promise,一旦结束状态完全可见并且可供用户交互时就会被解决。

它只有在updateCallback返回了一个被拒绝的 Promise 时才会被拒绝,因为这表明未能创建结束状态。

否则,如果过渡未能开始,或被跳过(通过skipTransition()),结束状态仍然会达到,因此finished会被解决。

viewTransition.skipTransition()

立即完成过渡,或者阻止其开始。

这永远不会阻止updateCallback的调用,因为 DOM 更改独立于过渡。有关此原则的更多详细信息,请参见§ 1.4 作为增强的过渡

如果在ready解决之前调用此方法,ready将被拒绝。

如果finished尚未解决,它将与updateCallbackDone一起解决或被拒绝。

一个 ViewTransition 拥有以下内容:

命名元素(named elements)

一个映射(map),其键为视图过渡名称(view transition name),值为被捕获的元素(captured elements)。初始时为一个新的映射(map)
注:由于该属性与 ViewTransition 相关联,当调用 清除视图过渡(Clear view transition) 时会被清理。

阶段(phase)

以下有序阶段之一,初始为 "pending-capture":

  1. "pending-capture"。

  2. "update-callback-called"。

  3. "animating"。

  4. "done"。

注意:对大多数开发者来说,使用该 API 时无需关心各个阶段,因为它们会自动推进。但了解每个阶段发生的步骤(如快照何时捕获、伪元素 DOM 何时创建等)很重要。下文对各个阶段的描述力求精确,旨在为实现者提供明确的规范实现步骤。

更新回调(update callback)

一个 UpdateCallback 或 null,初始为 null。

ready promise

一个 Promise。初始为 新建的 Promise,位于 当前对象相关 Realm 中。

update callback done promise

一个 Promise。初始为 新建的 Promise,位于 当前对象相关 Realm 中。

注意:ready promiseupdate callback done promise 会被立即创建,因此如果 Promise 被拒绝(rejection),会产生 unhandledrejection,除非被 处理,即使未访问 updateCallbackDone 等 getter。

finished promise

一个 Promise。初始为 新建的 Promise,位于 当前对象相关 Realm标记为已处理

注意:此 Promise 被标记为已处理,以避免重复的 unhandledrejection,因为该 Promise 只会随着 update callback done promise 一起被拒绝。

过渡根伪元素(transition root pseudo-element)

一个 ::view-transition。初始为新的 ::view-transition

初始快照包含块尺寸(initial snapshot containing block size)

一个包含两个数字(宽度和高度)的元组(tuple),或 null。初始为 null。

注意:用于检测快照包含块尺寸的变化,若变化则会导致该过渡被跳过相关讨论

finishedgetter 步骤为返回 当前对象finished promise

readygetter 步骤为返回 当前对象ready promise

updateCallbackDonegetter 步骤为返回 当前对象update callback done promise

6.2.1. skipTransition() 方法步骤

方法步骤(method steps)如下,适用于 skipTransition()

  1. 如果当前对象(this)阶段(phase)不是 "done",则用 "AbortError" DOMException,为当前对象跳过视图过渡(skip the view transition)

7. 算法

7.1. 数据结构

7.1.1. Document 的扩展

Document 还具有以下内容:

激活视图过渡(active view transition)

一个 ViewTransition 或 null。初始为 null。

视图过渡的渲染抑制(rendering suppression for view transitions)

一个布尔值。初始为 false。

Document视图过渡的渲染抑制 为 true 时, 所有指针命中测试都必须只针对其 文档元素(document element), 忽略其它所有元素

注意:这不会影响已被捕获(captured)的指针。

动态视图过渡样式表(dynamic view transition style sheet)

一个样式表(style sheet)。初始为用户代理源(user-agent origin)中新建的样式表,排序在全局视图过渡用户代理样式表之后。

注意:该样式表用于保存与过渡相关的动态样式。

显示视图过渡树(show view transition tree)

一个布尔值。初始为 false。

当其值为 true 时,当前对象激活视图过渡过渡根伪元素(transition root pseudo-element) 会作为 当前对象文档元素的子元素渲染,其 文档元素 是其 原始元素(originating element)

注意:过渡根伪元素文档元素中的位置无关紧要,因为该伪元素的包含块(containing block)快照包含块(snapshot containing block)

7.1.2. 元素的扩展

元素具有一个 在视图过渡中捕获 的布尔值,初始值为 false。

注意:此规范使用 CSS 对 元素 的定义,其中包括 伪元素

7.1.3. 捕获元素

捕获元素是一个具有以下内容的 结构体

旧图像(old image)

一个 2D 位图或 null。初始为 null。

旧宽度(old width)
旧高度(old height)

一个 unrestricted double,初始为 0。

旧变换(old transform)

一个 <transform-function>,初始为恒等变换函数(identity transform function)

旧 writing-mode

null 或 writing-mode,初始为 null。

旧 direction

null 或 direction,初始为 null。

旧 text-orientation

null 或 text-orientation,初始为 null。

旧 mix-blend-mode

null 或 mix-blend-mode,初始为 null。

旧 backdrop-filter

null 或 backdrop-filter,初始为 null。

旧 color-scheme

null 或 color-scheme,初始为 null。

新元素(new element)

一个元素(element)或 null。初始为 null。

此外,捕获元素 具有以下 样式定义

组关键帧

一个 CSSKeyframesRule 或 null。初始值为 null。

组动画名称规则

一个 CSSStyleRule 或 null。初始值为 null。

组样式规则

一个 CSSStyleRule 或 null。初始值为 null。

图像对隔离规则

一个 CSSStyleRule 或 null。初始值为 null。

图像动画名称规则

一个 CSSStyleRule 或 null。初始值为 null。

注意:这些用于从 文档动态视图过渡样式表 中更新并稍后移除样式。

7.2. 执行待定的过渡操作

此算法作为 HTML 规范中 更新渲染循环(update the rendering loop) 的一部分被调用。

执行待处理过渡操作(perform pending transition operations),给定一个 Document document,执行以下步骤:

  1. 如果 document激活视图过渡(active view transition) 不为 null,则:

    1. 如果 document激活视图过渡阶段(phase)为 "pending-capture",则为 document激活视图过渡 设置视图过渡(setup view transition)

    2. 否则,如果 document激活视图过渡阶段(phase)为 "animating",则为 document激活视图过渡 处理过渡帧(handle transition frame)

7.3. 设置视图过渡

要为 setup view transitionViewTransition transition, 执行以下步骤:

注意: 该算法捕获文档的当前状态, 调用过渡的 UpdateCallback, 然后捕获文档的新状态。

  1. documenttransition相关全局对象(relevant global object)关联文档(associated document)

  2. transition 捕获旧状态(Capture the old state)

    如果返回失败,则用 "InvalidStateError" DOMExceptiontransition相关 Realm 跳过视图过渡(skip the view transition),然后返回。

  3. document视图过渡的渲染抑制(rendering suppression for view transitions) 设为 true。

  4. DOM 操作任务源(DOM manipulation task source)上, 针对 transition相关全局对象排队一个全局任务(Queue a global task),以执行以下步骤:

    注意: 此处排队任务是因为在捕获图像时纹理读取可能是异步的,尽管 HTML 规范中的渲染步骤表现为同步。

    1. 如果 transition阶段(phase)为 "done",则中止这些步骤。

      注意: 如果 transition 在此之前已被跳过,就会发生这种情况。

    2. 调用更新回调(call the update callback)

要为 activate view transitionViewTransition transition, 执行以下步骤:
  1. 如果 transition阶段(phase)为 "done",则返回。

    注意: 如果 transition 在此之前被跳过,就会发生这种情况。

  2. 视图过渡的渲染抑制(rendering suppression for view transitions) 设为 false。

  3. 如果 transition初始快照包含块尺寸(initial snapshot containing block size) 不等于 快照包含块尺寸(snapshot containing block size),则为 transition 跳过视图过渡,并返回。

  4. transition 捕获新状态(Capture the new state)

    如果返回失败,则用 "InvalidStateError" DOMExceptiontransition相关 Realm 跳过视图过渡,然后返回。

  5. 解决(Resolve) transitionupdate callback done promise,值为 undefined。

  6. 对于每个 capturedElement 属于 transition命名元素(named elements)

    1. 如果 capturedElement新元素(new element) 不为 null,则将 capturedElement新元素视图过渡捕获状态(captured in a view transition) 设为 true。

  7. transition 设置过渡伪元素(Setup transition pseudo-elements)

  8. transition 更新伪元素样式(Update pseudo-element styles)

    如果返回失败,则用 "InvalidStateError" DOMExceptiontransition相关 Realm 跳过视图过渡,然后返回。

    注意: 上述步骤需要运行文档生命周期阶段,以计算样式/布局过程中产生的信息。

  9. transition阶段(phase)设为 "animating"。

  10. 解决(Resolve) transitionready promise

7.3.1. 捕获旧状态

要为 捕获旧状态ViewTransition transition
  1. documenttransition相关全局对象(relevant global object)关联文档(associated document)

  2. namedElementstransition命名元素(named elements)

  3. usedTransitionNames 为新的字符串集合(set)

  4. captureElements 为新的元素列表(list)

  5. documenttransition相关全局对象关联文档

  6. 如果快照包含块尺寸(snapshot containing block size)超过实现自定义(implementation-defined)的最大值,则返回失败。

  7. transition初始快照包含块尺寸(initial snapshot containing block size) 设为快照包含块尺寸

  8. 对于每个 element,属于所有已连接的元素(connected element)并且其节点文档等于 document,按绘制顺序(paint order)遍历:

    以绘制顺序遍历,确保该顺序被缓存于 namedElements。这定义了 ::view-transition-group 伪元素的 DOM 顺序,使得在绘制栈底部的元素会生成 ::view-transition 的第一个伪子元素。
    1. 如果该 element 的任何平坦树(flat tree)祖先跳过其内容(skips its contents),则继续(continue)

    2. 如果 element 有多个盒片段(box fragment),则继续

      注意:未来版本可能会支持对分片元素的过渡。参见 #8900

      注意:此处的盒片段并不指跨行内盒行盒分片,此类行内元素可以参与过渡。

    3. transitionNameelementview-transition-name计算值(computed value)

    4. 如果 transitionNamenone,或 element 未被渲染(not rendered),则继续

    5. 如果 usedTransitionNames 包含 transitionName,则返回失败。

    6. 添加 transitionNameusedTransitionNames

    7. element视图过渡捕获状态(captured in a view transition) 设为 true。

    8. 添加 elementcaptureElements

    算法将继续执行一个独立循环,以确保所有参与捕获的元素的 视图过渡捕获状态 都被设为 true,然后再被后续步骤读取。
  9. 对于每个 element 属于 captureElements

    1. capture 为新的捕获元素结构体(captured element struct)

    2. capture旧图像(old image) 设为 捕获 element 图像 的结果。

    3. originalRect 为,如果 element文档元素(document element),则为快照包含块(snapshot containing block),否则为该元素的边框盒(border box)

    4. capture旧宽度(old width) 设为 originalRectwidth

    5. capture旧高度(old height) 设为 originalRectheight

    6. capture旧变换(old transform) 设为一个 <transform-function>,该函数会将 element边框盒(border box)快照包含块原点(snapshot containing block origin)映射到其当前视觉位置。

    7. capture旧 writing-mode 设为 elementwriting-mode计算值

    8. capture旧 direction 设为 elementdirection计算值

    9. capture旧 text-orientation 设为 elementtext-orientation计算值

    10. capture旧 mix-blend-mode 设为 elementmix-blend-mode计算值

    11. capture旧 backdrop-filter 设为 elementbackdrop-filter计算值

    12. capture旧 color-scheme 设为 elementcolor-scheme计算值

    13. transitionNameelementview-transition-name计算值

    14. namedElements[transitionName] 设为 capture

  10. 对于每个 element 属于 captureElements

    1. element视图过渡捕获状态(captured in a view transition) 设为 false。

7.3.2. 捕获新状态

要为 捕获新状态ViewTransition transition
  1. documenttransition相关全局对象(relevant global object)关联文档(associated document)

  2. namedElementstransition命名元素(named elements)

  3. usedTransitionNames 为新的字符串集合(set)

  4. 对于每个 element,属于所有已连接的元素(connected element),且其节点文档等于 document,按绘制顺序(paint order)遍历:

    1. 如果该 element 的任何平坦树(flat tree)祖先跳过其内容(skips its contents),则继续(continue)

    2. transitionNameelementview-transition-name计算值(computed value)

    3. 如果 transitionNamenone,或 element 未被渲染(not rendered),则继续

    4. 如果 usedTransitionNames 包含 transitionName,则返回失败。

    5. 添加 transitionNameusedTransitionNames

    6. 如果 namedElements[transitionName] 不存在,则将 namedElements[transitionName] 设为新的捕获元素结构体(captured element struct)

      注意:我们特意将该结构体加入有序映射的末尾。这意味着仅存在于新 DOM 的名称(入场动画)会绘制在仅存在于旧 DOM 的名称(离场动画)和同时存在于新旧 DOM 的名称(配对动画)之上。这未必适用于所有分层情况,参见issue 8941

    7. namedElements[transitionName] 的 新元素(new element) 设为 element

7.3.3. 设置过渡伪元素

要为 设置过渡伪元素ViewTransition transition

注意:该算法构建了用于过渡的伪元素树,并生成了初始样式。 伪树的结构在更高级别的 § 3.2 视图过渡伪元素 中介绍。

  1. document当前对象(this)相关全局对象关联文档(associated document)

  2. document显示视图过渡树(show view transition tree)设为 true。

  3. 对于每对 transitionNamecapturedElement 属于 transition命名元素(named elements)

    1. group 为新的 ::view-transition-group(),其 视图过渡名称(view transition name) 设为 transitionName

    2. group 添加到 transition过渡根伪元素(transition root pseudo-element)

    3. imagePair 为新的 ::view-transition-image-pair(),其 视图过渡名称 设为 transitionName

    4. imagePair 添加到 group

    5. 如果 capturedElement旧图像(old image) 不为 null,则:

      1. old 为新的 ::view-transition-old(),其 视图过渡名称 设为 transitionName,并以 capturedElement旧图像 作为其 替换内容(replaced content)显示。

      2. old 添加到 imagePair

    6. 如果 capturedElement新元素(new element) 不为 null,则:

      1. new 为新的 ::view-transition-new(),其 视图过渡名称 设为 transitionName

        注意:该伪元素的样式由 更新伪元素样式(update pseudo-element styles)处理。

      2. new 添加到 imagePair

    7. 如果 capturedElement旧图像为 null,则:

      1. 断言(Assert)capturedElement新元素 不为 null。

      2. capturedElement图像动画名称规则(image animation name rule) 设为新的 CSSStyleRule,表示如下 CSS,并添加到 document动态视图过渡样式表(dynamic view transition style sheet)

        :root::view-transition-new(transitionName) {
          animation-name: -ua-view-transition-fade-in;
        }
        

        注意:上述代码示例包含待替换的变量。

    8. 如果 capturedElement新元素为 null,则:

      1. 断言capturedElement旧图像 不为 null。

      2. capturedElement图像动画名称规则 设为新的 CSSStyleRule,表示如下 CSS,并添加到 document动态视图过渡样式表

        :root::view-transition-old(transitionName) {
          animation-name: -ua-view-transition-fade-out;
        }
        

        注意:上述代码示例包含待替换的变量。

    9. 如果 capturedElement旧图像新元素均不为 null,则:

      1. transformcapturedElement旧变换(old transform)

      2. widthcapturedElement旧宽度(old width)

      3. heightcapturedElement旧高度(old height)

      4. backdropFiltercapturedElement旧 backdrop-filter

      5. capturedElement组关键帧规则(group keyframes) 设为新的 CSSKeyframesRule,表示如下 CSS,并添加到 document动态视图过渡样式表

        @keyframes -ua-view-transition-group-anim-transitionName {
          from {
            transform: transform;
            width: width;
            height: height;
            backdrop-filter: backdropFilter;
          }
        }
        

        注意:上述代码示例包含待替换的变量。

      6. capturedElement组动画名称规则(group animation name rule) 设为新的 CSSStyleRule,表示如下 CSS,并添加到 document动态视图过渡样式表

        :root::view-transition-group(transitionName) {
          animation-name: -ua-view-transition-group-anim-transitionName;
        }
        

        注意:上述代码示例包含待替换的变量。

      7. capturedElement图像对隔离规则(image pair isolation rule) 设为新的 CSSStyleRule,表示如下 CSS,并添加到 document动态视图过渡样式表

        :root::view-transition-image-pair(transitionName) {
          isolation: isolate;
        }
        

        注意:上述代码示例包含待替换的变量。

      8. capturedElement图像动画名称规则 设为新的 CSSStyleRule,表示如下 CSS,并添加到 document动态视图过渡样式表

        :root::view-transition-old(transitionName) {
          animation-name: -ua-view-transition-fade-out, -ua-mix-blend-mode-plus-lighter;
        }
        :root::view-transition-new(transitionName) {
          animation-name: -ua-view-transition-fade-in, -ua-mix-blend-mode-plus-lighter;
        }
        

        注意:上述代码示例包含待替换的变量。

        注意:mix-blend-mode: plus-lighter 可确保旧图像和新图像相同像素的混合结果为相同色值,实现“正确”的交叉淡入淡出。

7.4. 调用更新回调

调用更新回调(call the update callback),针对 ViewTransition transition,执行如下步骤:

注意: 该步骤对每一个 ViewTransition 都保证会被调用,即使该过渡已被跳过。原因详见 § 1.4 作为增强的过渡

  1. 断言transition阶段(phase)为 "done",或在 "update-callback-called" 之前。

  2. callbackPromise 为 null。

  3. 如果 transition更新回调(update callback)为 null,则将 callbackPromise 设为 解析为 undefined 的 promise,位于 transition相关 Realm

  4. 否则,将 callbackPromise 设为调用 transition更新回调的结果。

  5. 如果 transition阶段不是 "done",则将其 阶段设为 "update-callback-called"。

  6. fulfillSteps 为以下步骤:

    1. 激活视图过渡(Activate view transition) transition

    2. 解决(Resolve) transitionupdate callback done promise,值为 undefined。

      注意:若上一步已解决该 promise,则本步无影响。

  7. rejectSteps 为下列步骤,参数为 reason

    1. 拒绝(Reject) transitionupdate callback done promise,原因为 reason

    2. 如果 transition阶段为 "done",则返回。

      注意:如果 transition 在此之前被跳过,就会发生这种情况。

    3. 标记为已处理(Mark as handled) transitionready promise

      注意:transitionupdate callback done promise 会提供 unhandledrejection。本步避免重复。

    4. 跳过视图过渡(Skip the view transition) transition,并传入 reason

  8. 监听 callbackPromise,当其解决时执行 fulfillSteps,拒绝时执行 rejectSteps

  9. 如需在超时后跳过过渡,用户代理可并行执行以下步骤:

    1. 等待一个实现自定义的时长(duration)

    2. DOM 操作任务源(DOM manipulation task source)上, 针对 transition相关全局对象排队一个全局任务(Queue a global task),以执行以下步骤:

      1. 如果 transition阶段为 "done",则返回。

        注意:如果 transition 在此之前被跳过,就会发生这种情况。

      2. 跳过 transition,并抛出 "TimeoutError" DOMException

7.5. 跳过视图过渡

要为 ViewTransition transition 使用原因 reason 跳过视图过渡
  1. 设定变量 documenttransition相关全局对象关联文档

  2. 断言: transition阶段不是 "完成"。

  3. 如果 transition阶段处于 "调用更新回调之前",则在 transition相关全局对象的基础上,队列一个全局任务DOM 操作任务来源,以调用更新回调

  4. 视图过渡的渲染抑制设置为 false。

  5. 如果 document活动视图过渡transition,则清除视图过渡 transition

  6. transition阶段设置为 "完成"。

  7. 拒绝 transition准备 promise,原因是 reason

    注意:准备 promise可能已经在此时被解析, 如果在开始动画后调用 skipTransition(), 则此步骤将无效。

  8. 解析 transition完成 promise,以 响应 transition更新回调完成的 promise的结果:

    • 如果 promise 被满足,则返回 undefined。

    注意: 由于 transition更新回调完成 promise 的拒绝未被显式处理, 如果 transition更新回调完成 promise被拒绝, 则 transition完成 promise将以相同原因被拒绝。

7.6. 视图过渡页面可见性变化步骤

给定 视图过渡页面可见性变化步骤 Document document 为:
  1. 如果 document可见状态是 "隐藏",则:

    1. 如果 document活动视图过渡不是 null,则使用 "InvalidStateError" DOMException 跳过 document活动视图过渡

  2. 否则,断言活动视图过渡为空。

注意: 此步骤由 HTML 规范调用。

7.7. 捕获图像

捕获图像,给定一个元素 element,执行以下步骤。 它们返回一个图像。
  1. 如果 element文档元素,那么:

    1. 渲染文档的区域(包括其 画布背景和任何顶层内容), 该区域与 快照包含块相交, 在一个与 快照包含块大小相同的透明画布上, 按照捕获渲染特性及以下附加特性进行渲染:

      • 应将 element滚动框外部区域渲染为已滚动到的状态,而不移动或调整 布局视口的大小。 此操作不得触发与滚动或调整大小相关的事件,例如 IntersectionObserver

        手机浏览器窗口,显示一个URL栏,下方有一个固定位置的元素以及一些页面内容。滚动条指示页面已被显著滚动。 捕获的快照。显示URL栏下方的内容被包含在捕获中。
        用户看到的内容与捕获的快照的示例。 此示例假设根元素是唯一具有过渡名称的元素。
      • 不能滚动到的区域(即超出滚动边界的区域), 应渲染为画布背景

        手机浏览器窗口,显示一个URL栏和下方的一些内容。滚动条指示页面已滚动到顶部。 捕获的快照。显示URL栏下方区域与文档的其他部分颜色相同。
        用户看到的内容与捕获的快照的示例。 此示例假设根元素是唯一具有过渡名称的元素。
    2. 将此画布作为图像返回。 图像的自然大小等于 快照包含块

  2. 否则:

    1. 渲染 element 及其 后代, 按其在节点文档中显示的大小进行渲染, 在一个无限透明画布上, 按照捕获渲染特性进行渲染。

    2. 将此画布中包含 element墨水溢出矩形的部分作为图像返回。 此图像的自然尺寸必须是其边框盒的尺寸, 且其原点必须与此 边框盒的原点相对应, 以使图像表示此 边框盒的内容,且任何捕获的 墨水溢出在这些边界之外表示。

      注意: 当此图像以其自然大小作为替换元素渲染时, 它将显示元素的 主盒的大小和内容, 捕获的 墨水溢出将溢出其内容盒

7.7.1. 捕获渲染特性

捕获渲染特性如下:

7.8. 处理过渡帧

处理过渡帧,给定一个ViewTransition transition
  1. 设定变量 documenttransition相关全局对象关联文档

  2. 设定 hasActiveAnimations 为布尔值,初始值为 false。

  3. 对于每个 elementtransition过渡根伪元素包含后代

    1. 对于每个 animation,其 时间轴 是与 document 关联的 文档时间轴, 并包含至少一个 关联效果, 其 效果目标element, 如果以下任何条件为真,则将 hasActiveAnimations 设置为 true:

  4. 如果 hasActiveAnimations 为 false:

    1. transition阶段 设置为 "完成"。

    2. 清除视图过渡 transition

    3. 解析 transition完成的 promise

    4. 返回。

  5. 如果 transition初始快照包含块大小 不等于 快照包含块大小, 则跳过视图过渡 transition,并返回。

  6. 更新伪元素样式 transition

    如果返回失败,则跳过视图过渡 transition,并在 transition相关领域中返回 "InvalidStateError" DOMException

    注意: 上述内容表明,传入元素的大小或位置的变化将导致生成新的关键帧。 这可能导致视觉跳跃。 我们可以平滑地重新定位,但没有用例来证明其复杂性的合理性。 有关详细信息,请参阅 第7813号问题

7.9. 更新伪元素样式

更新伪元素样式,对于ViewTransition transition
  1. 对于每个 transitionNamecapturedElementtransition命名元素

    1. width, height, transform, writingMode, direction, textOrientation, mixBlendMode, backdropFiltercolorScheme 设置为 null。

    2. 如果 capturedElement新元素 为 null,那么:

      1. width 设置为 capturedElement旧宽度

      2. height 设置为 capturedElement旧高度

      3. transform 设置为 capturedElement旧变换

      4. writingMode 设置为 capturedElement旧写入模式

      5. direction 设置为 capturedElement旧方向

      6. textOrientation 设置为 capturedElement旧文本方向

      7. mixBlendMode 设置为 capturedElement旧混合模式

      8. backdropFilter 设置为 capturedElement旧背景滤镜

      9. colorScheme 设置为 capturedElement旧配色方案

    3. 否则:

      1. 如果以下任何条件为真,则返回失败:

        注意: 其他渲染约束通过 capturedElement新元素捕获在视图过渡中 强制执行。

      2. width 设置为 capturedElement新元素边框盒 的当前宽度。

      3. height 设置为 capturedElement新元素边框盒 的当前高度。

      4. transform 设置为一个变换,以将capturedElement新元素边框盒快照包含块原点 映射到其当前视觉位置。

      5. writingMode 设置为 capturedElement计算值写入模式

      6. direction 设置为 capturedElement计算值方向

      7. textOrientation 设置为 capturedElement计算值文本方向

      8. mixBlendMode 设置为 capturedElement计算值混合模式

      9. backdropFilter 设置为 capturedElement计算值背景滤镜

      10. colorScheme 设置为 capturedElement计算值配色方案

    4. 如果 capturedElement组样式规则 为 null, 则将 capturedElement组样式规则 设置为一个新的 CSSStyleRule 表示以下 CSS, 并将其附加到 transition相关全局对象关联文档动态视图过渡样式表

      否则,更新 capturedElement组样式规则 以匹配以下 CSS:

      :root::view-transition-group(transitionName) {
        width: width;
        height: height;
        transform: transform;
        writing-mode: writingMode;
        direction: direction;
        text-orientation: textOrientation;
        mix-blend-mode: mixBlendMode;
        backdrop-filter: backdropFilter;
        color-scheme: colorScheme;
      }
      

      注意: 上述代码示例包含需要替换的变量。

    5. 如果 capturedElement新元素 不为 null,那么:

      1. 设定 new::view-transition-new() ,使用视图过渡名称 transitionName

      2. new替换元素 内容设置为通过 捕获图像 所得的结果, 即 capturedElement新元素

如果其效果可以被 Web API 观察到,则必须执行此算法以更新用户代理源中的样式。

注意:此类 Web API 的一个示例是 window.getComputedStyle(document.documentElement, "::view-transition")

7.10. 清除视图过渡

清除视图过渡,对于ViewTransition transition
  1. 设定变量 documenttransition相关全局对象关联文档

  2. 断言: document活动视图过渡transition

  3. 对于每个 capturedElementtransition命名元素

    1. 如果 capturedElement新元素 不为 null, 则将 capturedElement新元素捕获在视图过渡中 设置为 false。

    2. 对于每个 stylecapturedElement样式定义

      1. 如果 style 不为 null, 且 styledocument动态视图过渡样式表 中, 则从 document动态视图过渡样式表 中移除 style

  4. document显示视图过渡树 设置为 false。

  5. document活动视图过渡 设置为 null。

隐私考虑

本规范未引入新的隐私考虑。

安全考虑

使用捕获图像算法生成的图像可能包含跨域数据(如果文档嵌入了跨域资源)或敏感信息,如访问过的链接。实现必须确保这些数据无法被文档访问。这应该是可行的,因为在文档的默认渲染中,访问这些数据已经被阻止。

附录 A. 变更

本附录是信息性的。

2022-05-30 工作草案的变更

2022-05-25 工作草案的变更

2022-11-24 工作草案的变更

2022-10-25 工作草案 (FPWD)的变更

一致性

文档约定

一致性要求通过描述性断言和 RFC 2119 术语的组合来表达。本规范的规范部分中的关键字“必须”、“不可”、“要求”、“应当”、“不应当”、“建议”、“可以”和“可选”应按照 RFC 2119 的描述来解释。然而,为了提高可读性,这些词在本规范中不会全部以大写字母出现。

本规范的所有文本都是规范性的,除非明确标记为非规范性部分、示例和注释。[RFC2119]

本规范中的示例以“例如”开头,或通过 class="example" 与规范文本分开,例如:

这是一个说明性的示例。

说明性注释以“注意”开头,并通过 class="note" 与规范文本分开,例如:

注意,这是一个说明性注释。

建议性内容是以引起特别注意的样式设置的规范性部分,并通过 <strong class="advisement"> 与其他规范文本分开,例如: 用户代理必须提供一个可访问的替代方案。

一致性类

本规范的符合性定义为三种符合性类:

样式表
一个CSS 样式表
渲染器
一个用户代理(UA),用于解释样式表的语义并渲染使用它们的文档。
创作工具
一个用户代理(UA),用于编写样式表。

如果样式表中使用本模块定义的语法的所有语句根据通用 CSS 语法和本模块中每个特性定义的各自语法都是有效的,则该样式表符合本规范。

如果渲染器除了按照相应的规范定义解释样式表外,还正确解析本规范定义的所有特性并相应地渲染文档,则该渲染器符合本规范。然而,由于设备的限制,用户代理无法正确渲染文档的情况并不会使该用户代理不符合规范。(例如,用户代理不需要在单色显示器上渲染颜色。)

如果创作工具编写的样式表在语法上符合通用 CSS 语法和本模块中每个特性定义的各自语法,并满足本模块中描述的样式表的所有其他符合性要求,则该创作工具符合本规范。

部分实现

为了使作者能够利用向前兼容的解析规则分配后备值,CSS 渲染器必须将任何不支持的 at-rules、属性、属性值、关键字和其他语法结构视为无效(并适当忽略)。特别是,用户代理不得在单个多值属性声明中选择性地忽略不支持的组件值并采用支持的值:如果任何值被认为无效(如不支持的值必须是),CSS 要求忽略整个声明。

不稳定和专有特性的实现

为了避免与未来稳定的 CSS 特性发生冲突,CSS 工作组建议遵循最佳实践,以实现不稳定特性和CSS 的专有扩展

非实验性实现

一旦规范进入候选推荐阶段,就可以进行非实验性实现,且实现者应发布任何符合候选推荐级别的特性的不加前缀的实现,只要他们可以证明其符合规范地实现了这些特性。

为了建立和保持 CSS 在各实现间的互操作性,CSS 工作组请求非实验性的 CSS 渲染器在发布任何 CSS 特性的无前缀实现之前,向 W3C 提交实现报告(如果必要,还需提交用于该实现报告的测试用例)。提交给 W3C 的测试用例需经过 CSS 工作组的审核和修正。

有关提交测试用例和实现报告的更多信息,请访问 CSS 工作组的网站 https://www.w3.org/Style/CSS/Test/。问题请发送至 public-css-testsuite@w3.org 邮件列表。

候选推荐退出标准

要将此规范推进到提案推荐状态,每个特性必须至少有两个独立的、可互操作的实现。每个特性可以由不同的产品实现,不要求所有特性都由单个产品实现。为了满足此标准,我们定义以下术语:

独立的
每个实现必须由不同的团队开发,且不得共享、重用或派生于另一合格实现使用的代码。与本规范的实现无关的代码部分不受此要求的约束。
可互操作的
通过官方 CSS 测试套件中的相应测试用例,或者如果该实现不是 Web 浏览器,则通过等效测试。每个相关的测试用例都应该有一个等效的测试用例创建出来,以便该用户代理(UA)声称具有互操作性。此外,如果要使用这样的 UA 声称互操作性,那么还必须有一个或多个其他的 UA 也以相同的方式通过这些等效测试,以证明互操作性。这些等效测试必须公开以供同行评审。
实现
一个用户代理,其符合以下条件:
  1. 实现了规范。
  2. 对公众开放。该实现可以是已发布的产品或其他公开可用的版本(例如测试版本、预览版或“每夜构建”)。未发布的产品版本必须至少实现该特性一个月,以证明其稳定性。
  3. 不是实验性的(即不是专门为了通过测试套件而设计的版本,并且不打算用于将来的正常使用)。

该规范将至少保持候选推荐状态六个月。

索引

由本规范定义的术语

引用中定义的术语

参考文献

规范性引用

[COMPOSITING-1]
Chris Harrelson. Compositing and Blending Level 1. 21 March 2024. CR. URL: https://www.w3.org/TR/compositing-1/
[CSS-2022]
Tab Atkins Jr.; Elika Etemad; Florian Rivoal. CSS Snapshot 2022. 22 November 2022. NOTE. URL: https://www.w3.org/TR/css-2022/
[CSS-ANIMATIONS-1]
David Baron; et al. CSS Animations Level 1. 2 March 2023. WD. URL: https://www.w3.org/TR/css-animations-1/
[CSS-BACKGROUNDS-3]
Elika Etemad; Brad Kemper. CSS Backgrounds and Borders Module Level 3. 11 March 2024. CR. URL: https://www.w3.org/TR/css-backgrounds-3/
[CSS-BOX-4]
Elika Etemad. CSS Box Model Module Level 4. 3 November 2022. WD. URL: https://www.w3.org/TR/css-box-4/
[CSS-BREAK-4]
Rossen Atanassov; Elika Etemad. CSS Fragmentation Module Level 4. 18 December 2018. WD. URL: https://www.w3.org/TR/css-break-4/
[CSS-CASCADE-5]
Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. CSS Cascading and Inheritance Level 5. 13 January 2022. CR. URL: https://www.w3.org/TR/css-cascade-5/
[CSS-COLOR-4]
Chris Lilley; Tab Atkins Jr.; Lea Verou. CSS Color Module Level 4. 13 February 2024. CR. URL: https://www.w3.org/TR/css-color-4/
[CSS-COLOR-ADJUST-1]
Elika Etemad; et al. CSS Color Adjustment Module Level 1. 14 June 2022. CR. URL: https://www.w3.org/TR/css-color-adjust-1/
[CSS-CONTAIN-2]
Tab Atkins Jr.; Florian Rivoal; Vladimir Levin. CSS Containment Module Level 2. 17 September 2022. WD. URL: https://www.w3.org/TR/css-contain-2/
[CSS-DISPLAY-3]
Elika Etemad; Tab Atkins Jr.. CSS Display Module Level 3. 30 March 2023. CR. URL: https://www.w3.org/TR/css-display-3/
[CSS-IMAGES-3]
Tab Atkins Jr.; Elika Etemad; Lea Verou. CSS Images Module Level 3. 18 December 2023. CR. URL: https://www.w3.org/TR/css-images-3/
[CSS-IMAGES-4]
Tab Atkins Jr.; Elika Etemad; Lea Verou. CSS Images Module Level 4. 17 February 2023. WD. URL: https://www.w3.org/TR/css-images-4/
[CSS-MASKING-1]
Dirk Schulze; Brian Birtles; Tab Atkins Jr.. CSS Masking Module Level 1. 5 August 2021. CR. URL: https://www.w3.org/TR/css-masking-1/
[CSS-OVERFLOW-3]
Elika Etemad; Florian Rivoal. CSS Overflow Module Level 3. 29 March 2023. WD. URL: https://www.w3.org/TR/css-overflow-3/
[CSS-POSITION-3]
Elika Etemad; Tab Atkins Jr.. CSS Positioned Layout Module Level 3. 3 April 2023. WD. URL: https://www.w3.org/TR/css-position-3/
[CSS-POSITION-4]
CSS Positioned Layout Module Level 4. Editor's Draft. URL: https://drafts.csswg.org/css-position-4/
[CSS-PSEUDO-4]
Daniel Glazman; Elika Etemad; Alan Stearns. CSS Pseudo-Elements Module Level 4. 30 December 2022. WD. URL: https://www.w3.org/TR/css-pseudo-4/
[CSS-SCOPING-1]
Tab Atkins Jr.; Elika Etemad. CSS Scoping Module Level 1. 3 April 2014. WD. URL: https://www.w3.org/TR/css-scoping-1/
[CSS-TRANSFORMS-1]
Simon Fraser; et al. CSS Transforms Module Level 1. 14 February 2019. CR. URL: https://www.w3.org/TR/css-transforms-1/
[CSS-TRANSFORMS-2]
Tab Atkins Jr.; et al. CSS Transforms Module Level 2. 9 November 2021. WD. URL: https://www.w3.org/TR/css-transforms-2/
[CSS-UI-4]
Florian Rivoal. CSS Basic User Interface Module Level 4. 16 March 2021. WD. URL: https://www.w3.org/TR/css-ui-4/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 4. 12 March 2024. WD. URL: https://www.w3.org/TR/css-values-4/
[CSS-VIEWPORT-1]
Florian Rivoal; Emilio Cobos Álvarez. CSS Viewport Module Level 1. 25 January 2024. WD. URL: https://www.w3.org/TR/css-viewport-1/
[CSS-WRITING-MODES-3]
Elika Etemad; Koji Ishii. CSS Writing Modes Level 3. 10 December 2019. REC. URL: https://www.w3.org/TR/css-writing-modes-3/
[CSS-WRITING-MODES-4]
Elika Etemad; Koji Ishii. CSS Writing Modes Level 4. 30 July 2019. CR. URL: https://www.w3.org/TR/css-writing-modes-4/
[CSS2]
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. 7 June 2011. REC. URL: https://www.w3.org/TR/CSS21/
[CSS22]
Bert Bos. Cascading Style Sheets Level 2 Revision 2 (CSS 2.2) Specification. 12 April 2016. WD. URL: https://www.w3.org/TR/CSS22/
[CSSOM-1]
Daniel Glazman; Emilio Cobos Álvarez. CSS Object Model (CSSOM). 26 August 2021. WD. URL: https://www.w3.org/TR/cssom-1/
[CSSOM-VIEW-1]
Simon Pieters. CSSOM View Module. 17 March 2016. WD. URL: https://www.w3.org/TR/cssom-view-1/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[FILTER-EFFECTS-1]
Dirk Schulze; Dean Jackson. Filter Effects Module Level 1. 18 December 2018. WD. URL: https://www.w3.org/TR/filter-effects-1/
[FILTER-EFFECTS-2]
Filter Effects Module Level 2. Editor's Draft. URL: https://drafts.fxtf.org/filter-effects-2/
[GEOMETRY-1]
Simon Pieters; Chris Harrelson. Geometry Interfaces Module Level 1. 4 December 2018. CR. URL: https://www.w3.org/TR/geometry-1/
[HR-TIME-3]
Yoav Weiss. High Resolution Time. 19 July 2023. WD. URL: https://www.w3.org/TR/hr-time-3/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[INTERSECTION-OBSERVER]
Stefan Zager; Emilio Cobos Álvarez; Traian Captan. Intersection Observer. 18 October 2023. WD. URL: https://www.w3.org/TR/intersection-observer/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[SELECTORS-3]
Tantek Çelik; et al. Selectors Level 3. 6 November 2018. REC. URL: https://www.w3.org/TR/selectors-3/
[SELECTORS-4]
Elika Etemad; Tab Atkins Jr.. Selectors Level 4. 11 November 2022. WD. URL: https://www.w3.org/TR/selectors-4/
[WEB-ANIMATIONS-1]
Brian Birtles; et al. Web Animations. 5 June 2023. WD. URL: https://www.w3.org/TR/web-animations-1/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

说明性引用

[CSS-SIZING-3]
Tab Atkins Jr.; Elika Etemad. CSS Box Sizing Module Level 3. 17 December 2021. WD. URL: https://www.w3.org/TR/css-sizing-3/
[POINTEREVENTS3]
Patrick Lauke; Robert Flack. Pointer Events. 18 March 2024. WD. URL: https://www.w3.org/TR/pointerevents3/
[SCROLL-ANIMATIONS-1]
Brian Birtles; et al. Scroll-driven Animations. 6 June 2023. WD. URL: https://www.w3.org/TR/scroll-animations-1/

属性索引

名称 初始值 适用于 继承 百分率 动画类型 规范顺序 计算值
view-transition-name none | <custom-ident> none 所有元素 不适用 离散 按语法 如指定

IDL索引

partial interface Document {
  ViewTransition startViewTransition(optional UpdateCallback updateCallback);
};

callback UpdateCallback = Promise<any> ();

[Exposed=Window]
interface ViewTransition {
  readonly attribute Promise<undefined> updateCallbackDone;
  readonly attribute Promise<undefined> ready;
  readonly attribute Promise<undefined> finished;
  undefined skipTransition();
};