view-transition-name

可用性有限

此特性不是基线特性,因为它在一些最广泛使用的浏览器中不起作用。

view-transition-name CSS 属性指定所选元素将参与的视图过渡快照。这使你可以将这些元素与页面的其余部分分开进行动画处理,而页面的其余部分在视图过渡期间使用默认的交叉淡入淡出动画。然后,你可以为这些元素定义自定义动画样式。

语法

css
/* <custom-ident> value examples */
view-transition-name: header;
view-transition-name: figure-caption;

/* Keyword value */
view-transition-name: none;
view-transition-name: match-element;

/* Global values */
view-transition-name: inherit;
view-transition-name: initial;
view-transition-name: revert;
view-transition-name: revert-layer;
view-transition-name: unset;

<custom-ident>

一个标识名称,使所选元素参与与根快照分离的快照。<custom-ident> 不能是 automatch-elementnoneCSS 全局关键字值。

match-element

浏览器会自动为所选元素分配一个唯一的名称。此名称用于将该元素与页面上所有其他元素分开进行快照。(此名称是内部的,无法从 DOM 读取。)

none

所选元素不会参与单独的快照,除非其父元素设置了 view-transition-name,在这种情况下,它将作为该元素的一部分进行快照。

描述

默认情况下,当视图过渡应用于 Web 应用时,在该过渡期间发生的所有 UI 更改都会被快照并一起进行动画处理。这是默认的——或称root)——快照(参见视图过渡伪元素树)。默认情况下,此动画是平滑的交叉淡入淡出,可以在视图过渡 SPA 演示中看到实际效果。

如果你希望某些元素在视图过渡期间与快照的动画方式不同,你可以通过为它们指定一个不同的 view-transition-name 来实现,例如

css
figcaption {
  view-transition-name: figure-caption;
}

然后,你可以使用相关的视图过渡伪元素——::view-transition-old()::view-transition-new()——来为旧快照和新快照指定你想要的动画。例如

css
::view-transition-old(figure-caption) {
  animation: 0.25s linear both shrink-x;
}

::view-transition-new(figure-caption) {
  animation: 0.25s 0.25s linear both grow-x;
}

如果你不希望某个元素被单独快照,可以指定 view-transition-name 的值为 none

css
.dont-animate-me {
  view-transition-name: none;
}

对于参与视图过渡的每个渲染元素,view-transition-name<custom-ident> 必须是唯一的。如果两个渲染元素在同一时间具有相同的 view-transition-nameViewTransition.ready Promise 将会拒绝,并且过渡将被跳过。

自动指定 view-transition-name

有时,你希望在视图过渡中为多个 UI 元素分别设置动画。当页面上有一个元素列表并且希望以某种方式重新排列它们时,通常就是这种情况

html
<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>

  <!-- ... -->

  <li>Item 99</li>
</ul>

为每个元素指定一个唯一的名称可能很不方便,尤其是在元素数量增多时

css
li:nth-child(1) {
  view-transition-name: item1;
}
li:nth-child(2) {
  view-transition-name: item2;
}
li:nth-child(3) {
  view-transition-name: item3;
}
li:nth-child(4) {
  view-transition-name: item4;
}

/* ... */

li:nth-child(99) {
  view-transition-name: item99;
}

为了解决这个问题,你可以使用 match-element 值,这会使浏览器为每个选定的元素指定一个唯一的内部 view-transition-name

css
li {
  view-transition-name: match-element;
}

由于 match-element 会根据元素标识自动分配 view-transition-name 值,因此它只能用于同文档视图过渡。自动生成的内部标识符无法在不同元素或文档之间传递。

正式定义

初始值none
应用于所有元素
继承性
计算值同指定值
动画类型离散

正式语法

view-transition-name = 
none |
<custom-ident>

示例

view-transition-name 的基本用法

此示例来自视图过渡 SPA 演示,这是一个基本的图片库。基本 SPA 视图过渡更详细地解释了此演示的工作原理。

大部分 UI 更改都使用过渡快照进行动画处理。然而,<figcaption> 被赋予了 figure-captionview-transition-name,以使其可以与页面的其余部分以不同的方式进行动画处理

css
figcaption {
  view-transition-name: figure-caption;
}

以下代码仅对 <figcaption> 应用自定义动画

css
@keyframes grow-x {
  from {
    transform: scaleX(0);
  }
  to {
    transform: scaleX(1);
  }
}

@keyframes shrink-x {
  from {
    transform: scaleX(1);
  }
  to {
    transform: scaleX(0);
  }
}

::view-transition-group(figure-caption) {
  height: auto;
  right: 0;
  left: auto;
  transform-origin: right center;
}

::view-transition-old(figure-caption) {
  animation: 0.25s linear both shrink-x;
}

::view-transition-new(figure-caption) {
  animation: 0.25s 0.25s linear both grow-x;
}

我们创建了一个自定义 CSS 动画,并将其应用于 ::view-transition-old(figure-caption)::view-transition-new(figure-caption) 伪元素。我们还应用了其他样式以将它们保持在同一位置,并防止默认样式干扰我们的自定义动画。

使用 match-element

此示例包含一个技术列表——HTML、CSS、SVG 和 JS——它们显示在主内容区域旁边的侧边栏中,而主内容区域最初是空的。点击某个技术的标题会将其内容动画化到显示更多详细信息的相邻内容区域中。

HTML

<main> 元素包含一个无序列表和一个 <article> 元素。列表中的多个子 <li> 元素各自包含一个位于标题内的 <a> 元素。

html
<main class="match-element-applied">
  <ul>
    <li>
      <h2><a href="#">HTML</a></h2>
      <h3>HyperText Markup Language</h3>
      <p>
        HyperText Markup Language (HTML) is the most basic building block of the
        web. It defines the meaning and structure of web content. HTML provides
        the fundamental building blocks for structuring web documents and apps.
      </p>
    </li>
    <li>
      <h2><a href="#">CSS</a></h2>
      <h3>Cascading Style Sheets</h3>
      <p>
        Cascading Style Sheets (CSS) is a stylesheet language used to describe
        the presentation of a document written in HTML or XML (including XML
        dialects such as SVG, MathML or XHTML). CSS describes how elements
        should be rendered on screen, on paper, in speech, or on other media.
      </p>
    </li>
    <li>
      <h2><a href="#">SVG</a></h2>
      <h3>Scalable Vector Graphics</h3>
      <p>
        Scalable Vector Graphics (SVG) is an XML-based markup language for
        describing two-dimensional based vector graphics.
      </p>
    </li>
    <li>
      <h2><a href="#">JS</a></h2>
      <h3>JavaScript</h3>
      <p>
        JavaScript (JS) is the web's native programming language. JavaScript is
        a lightweight, interpreted (or just-in-time compiled) programming
        language with first-class functions. While it is most well-known as the
        scripting language for web pages, many non-browser environments, such as
        Node.js, also use it.
      </p>
    </li>
  </ul>
  <article></article>
</main>

CSS

我们使用 Flexbox 来将 <li><article> 并排布局,并使列表项在第一列中共享相等的空间。列表占据容器宽度的 35%,而 <article> 则填充剩余的可用水平空间。

css
main {
  container-type: inline-size;
  width: 100%;
  height: 100%;
  display: flex;
  gap: 2cqw;
  position: relative;
}

ul {
  width: 35cqw;
  display: flex;
  flex-direction: column;
  gap: 1cqw;
}

article {
  flex: 1;
}

li {
  flex: 1;
}

我们还定义了一个规则,用于选择具有 active-item 类的元素。当此类别应用于某个元素时,该规则会使其精确定位在 <article> 元素的正上方。当列表项的链接被点击时,将通过 JavaScript 将此类应用于列表项,这将启动一个视图过渡。

css
.active-item {
  position: absolute;
  z-index: 1;
  translate: 37cqw;
  width: calc(100% - 37cqw);
  height: 100%;
}

默认情况下,视图过渡中的所有元素都会在一个交叉淡入淡出中一起进行动画处理。然而,在此示例中,我们不希望这样——我们希望每个列表项都有自己的移动动画。我们可以通过对每个列表项应用 view-transition-name: match-element 来实现这一点

css
.match-element-applied li {
  view-transition-name: match-element;
}

match-element-applied 类默认应用于 <main> 元素,这就是为什么“结果”框架中的复选框最初是选中的。如果取消选中它,该类将被移除,默认的交叉淡入淡出动画将生效。你可以切换复选框来比较默认动画和使用 view-transition-name: match-element 时应用的动画。

接下来,我们通过使用 ::view-transition-group() 伪元素为所有视图过渡组(由 * 标识符表示)应用 animation-duration,并为所有旧快照和新快照设置 height100%,来自定义动画。这可以解决旧快照和新快照宽高比差异的问题,并使动画看起来更平滑

css
::view-transition-group(*) {
  animation-duration: 0.5s;
}

html::view-transition-old(*),
html::view-transition-new(*) {
  height: 100%;
}

JavaScript

在此示例中,当列表项的链接被点击时,active-item 类会应用于这些列表项;这是通过 updateActiveItem() 函数实现的

js
const mainElem = document.querySelector("main");
let prevElem;
let checkboxElem = document.querySelector("input");

// View transition code
function updateActiveItem(event) {
  // Get the list item that contains the clicked link
  const clickedElem = event.target.parentElement.parentElement;

  // Set the active-item class on the list item
  clickedElem.className = "active-item";

  // Keep track of the previous item that was clicked, if any.
  // Remove the active-item class from the previous item so that only
  // one list item is placed over the <article> at any one time
  if (prevElem === clickedElem) {
    prevElem.className = "";
    prevElem = undefined;
  } else if (prevElem) {
    prevElem.className = "";
    prevElem = clickedElem;
  } else {
    prevElem = clickedElem;
  }
}

mainElem.addEventListener("click", (event) => {
  event.preventDefault(); // Prevent iframe from scrolling when clicked
  // Do nothing unless a link is clicked inside the <main> element
  if (event.target.tagName !== "A") {
    return;
  }

  // Run updateActiveItem() on its own if view transitions are not supported
  if (!document.startViewTransition) {
    updateActiveItem(event);
  } else {
    // Run updateActiveItem() via startViewTransition()
    const transition = document.startViewTransition(() =>
      updateActiveItem(event),
    );
  }
});

// Toggle the class on <main> to control whether or not match-element is applied

checkboxElem.addEventListener("change", () => {
  mainElem.classList.toggle("match-element-applied");
});

通过 startViewTransition() 函数运行 updateActiveItem() 函数可以平滑地动画化技术详情的显示。

结果

点击侧边栏中的一个技术标题,注意其内容进入主内容区域的动画效果。

还有一个复选框,默认是选中的,因此应用了 view-transition-name: match-element。取消选中该复选框,然后再次点击一个标题,看看在没有 view-transition-name: match-element 的情况下视图过渡是如何工作的。

规范

规范
CSS 视图过渡模块第 1 级
# view-transition-name-prop

浏览器兼容性

另见