四个新的 CSS 功能,可实现流畅的进入和退出动画

动效是任何数字体验的核心部分,可引导用户从一次互动过渡到下一次互动。不过,在 Web 平台上,流畅的动画会出现一些空白。这些功能包括能够轻松为进入和退出动画添加动画效果,以及为对话框和弹出式窗口等可关闭元素在顶层之间添加平滑的动画效果。

为了填补这些空白,Chrome 116 和 117 中包含四项新的 Web 平台功能,可为离散属性实现流畅的动画和转场效果。

这四项新功能包括:

  • 能够在关键帧时间轴上为 displaycontent-visibility 添加动画效果(从 Chrome 116 开始)。
  • 使用 allow-discrete 关键字的 transition-behavior 属性,用于启用 display 等离散属性的转换(从 Chrome 117 开始)。
  • 用于为从 display: none 进入顶层的进入效果添加动画的 @starting-style 规则(从 Chrome 117 开始)。
  • overlay 属性,用于控制动画期间顶层的行为(从 Chrome 117 开始)。

在关键帧中显示动画

从 Chrome 116 开始,您可以在关键帧规则中使用 displaycontent-visibility。然后,这些元素会在关键帧出现时进行切换。无需额外的新值即可支持此功能:

.card {
  animation: fade-out 0.5s forwards;
}

@keyframes fade-out {
  100% {
    opacity: 0;
    display: none;
  }
}

上例在 0.5 秒的时长内将不透明度以动画形式呈现为 0,然后将“display”设置为“none”。此外,forwards 关键字可确保动画保持其结束状态,以便应用于它的元素保持 display: noneopacity: 0

这是一个简单的示例,它模拟了您可以使用过渡效果执行哪些操作(请参阅“过渡”部分中的演示)。不过,转场效果无法制作更复杂的动画,例如以下示例:

.card {
  animation: spin-and-delete 1s ease-in forwards;
}

@keyframes spin-and-delete {
  0% {
    transform: rotateY(0);
    filter: hue-rotate(0);
  }
  80% {
    transform: rotateY(360deg);
    filter: hue-rotate(180deg);
    opacity: 1;
  }
  100% {
    opacity: 0;
    display: none;
  }
}

spin-and-delete 动画是退出动画。首先,卡片将沿 y 轴旋转,旋转一次色调,然后在 80% 处将卡片不透明度从 1 转换为 0。最后,卡片从 display: block 切换为 display: none

对于这些退出动画,您可以为动画设置触发器,而不是将其直接应用于元素。例如,将事件监听器附加到触发某个类应用动画的按钮,如下所示:

.spin-out {
   animation: spin-and-delete 1s ease-in forwards;
}
document.querySelector('.delete-btn').addEventListener('click', () => {
 document.querySelector('.card').classList.add('spin-out');
})

现在,上面的示例的最终状态为 display:none。在很多情况下,您需要更进一步,移除设有超时的 DOM 节点,以便先播放动画。

转换离散动画

与使用关键帧为离散属性添加动画效果不同,如需为离散属性添加转场效果,您需要使用 allow-discrete 转场行为模式。

transition-behavior 属性

allow-discrete 模式是实现离散转换的关键,也是 transition-behavior 属性的值。transition-behavior 接受两个值:normalallow-discrete

.card {
  transition: opacity 0.25s, display 0.25s;
  transition-behavior: allow-discrete; /* Note: be sure to write this after the shorthand */
}

.card.fade-out {
  opacity: 0;
  display: none;
}
注意:此过渡演示采用了与第一个动画演示不同的技术,但在视觉上看起来很相似。

transition 简写形式也会设置此值,因此您可以省略该属性,改为在每个转换的 transition 简写形式末尾使用 allow-discrete 关键字。

.card {
  transition: opacity 0.5s, display 0.5s allow-discrete;
}

.card.fade-out {
  opacity: 0;
  display: none;
}

如果您要为多个离散属性添加动画效果,则需要在要为其添加动画效果的每个属性后面添加 allow-discrete。例如:

.card {
  transition: opacity 0.5s, display 0.5s allow-discrete, overlay 0.5s allow-discrete;
}

.card.fade-out {
  opacity: 0;
  display: none;
}

进入动画的 @starting-style 规则

到目前为止,本文已经介绍了退出动画。如需创建进入动画,您需要使用 @starting-style 规则。

使用 @starting-style 应用一种样式,以便浏览器在网页上打开相应元素之前查找这些样式。这是“前打开”状态(即为制作动画而设置的)。

/*  0. IS-OPEN STATE   */
/*  The state at which the element is open + transition logic */
.item {
  height: 3rem;
  display: grid;
  overflow: hidden;
  transition: opacity 0.5s, transform 0.5s, height 0.5s, display 0.5s allow-discrete;
}

/*  1. BEFORE-OPEN STATE   */
/*  Starting point for the transition */
@starting-style {
  .item {
    opacity: 0;
    height: 0;
  }
}

/*  2. EXITING STATE   */
/*  While it is deleting, before DOM removal in JS, apply this
    transformation for height, opacity, and a transform which
    skews the element and moves it to the left before setting
    it to display: none */
.is-deleting {
  opacity: 0;
  height: 0;
  display: none;
  transform: skewX(50deg) translateX(-25vw);
}

现在,这些 TODO 列表项已具备进入和退出状态:

为元素添加从顶层进入和离开的动画效果

如需为元素添加从顶层进入和离开的动画效果,请在“open”状态下指定 @starting-style,以告知浏览器从哪里进入动画效果。对于对话框,打开状态是使用 [open] 属性定义的。对于弹出式窗口,请使用 :popover-open 伪类。

对话框的简单示例如下所示:

/*   0. IS-OPEN STATE   */
dialog[open] {
  translate: 0 0;
}

/*   1. BEFORE-OPEN STATE   */
@starting-style {
  dialog[open] {
    translate: 0 100vh;
  }
}

/*   2. EXIT STATE   */
dialog {
  transition: translate 0.7s ease-out, overlay 0.7s ease-out allow-discrete, display 0.7s ease-out allow-discrete;
  translate: 0 100vh;
}

在下一个示例中,进入和退出效果是不同的。进入时,从视口底部向上添加动画效果,退出效果到视口顶部。它还使用嵌套 CSS 编写,以实现更好的视觉封装。

为弹出式窗口添加动画效果时,请使用 :popover-open 伪类,而不是之前使用的 open 属性。

.settings-popover {
  &:popover-open {
    /*  0. IS-OPEN STATE  */
    /*  state when popover is open, BOTH:
        what we're transitioning *in* to 
        and transitioning *out* from */
    transform: translateY(0);
    opacity: 1;

    /*  1. BEFORE-OPEN STATE  */
    /*  Initial state for what we're animating *in* from, 
        in this case: goes from lower (y + 20px) to center  */
    @starting-style {
      transform: translateY(20px);
      opacity: 0;
    }
  }
  
  /*  2. EXIT STATE  */
  /*  Initial state for what we're animating *out* to , 
      in this case: goes from center to (y - 50px) higher */
  transform: translateY(-50px);
  opacity: 0;
  
  /*  Enumerate transitioning properties, 
      including display and allow-discrete mode */
  transition: transform 0.5s, opacity 0.5s, display 0.5s allow-discrete;
}

overlay 个房源

最后,如需从顶层淡出 popoverdialog,请将 overlay 属性添加到过渡列表中。popoverdialog 对祖先剪辑和转换进行转义,同时将内容放在顶层。如果您不对 overlay 进行转换,元素将立即恢复被剪裁、转换和遮盖的状态,并且您不会看到转换过程。

[open] {
  transition: opacity 1s, display 1s allow-discrete;
}

而是在过渡或动画中添加 overlay,以便将 overlay 与其余功能一起添加到动画中,并确保它在动画播放时保持在顶层。这样看起来会更加流畅。

[open] {
  transition: opacity 1s, display 1s allow-discrete, overlay 1s allow-discrete;
}

此外,当您在顶层打开多个元素时,叠加层有助于您控制进入和退出顶层的流畅过渡。您可以在这个简单的示例中看到差异。如果您在第二个弹出式窗口过渡时不向其应用 overlay,则它会先移出顶层,跳到另一个弹出式窗口后面,然后再开始过渡。这种效果不太流畅。

关于视图转换的注意事项

如果您要进行 DOM 更改(例如在 DOM 中添加和移除元素),视图转换是实现流畅动画的另一个绝佳解决方案。以下是上述两个使用 View 转换构建的示例。

在此第一个演示中,视图转场将处理转场,而无需设置 @starting-style 和其他 CSS 转换。视图转换的设置如下所示:

首先,在 CSS 中,为每张卡片分配一个单独的 view-transition-name

.card-1 {
  view-transition-name: card-1;
}

.card-2 {
  view-transition-name: card-2;
}

/* etc. */

然后,在 JavaScript 中,将 DOM 突变(在本例中为移除卡片)封装在视图转换中。

deleteBtn.addEventListener('click', () => {
  // Check for browser support
  if (document.startViewTransition) {
    document.startViewTransition(() => {
      // DOM mutation
      card.remove();
    });
  } 
  // Alternative if no browser support
  else {
    card.remove();
  }
})

现在,浏览器可以处理每个卡片淡出并变形到新位置。

这个 Pen

另一个适合使用此方法的示例是“添加/移除列表项”演示。在这种情况下,您需要记得为创建的每张卡片添加唯一的 view-transition-name

总结

这些新的平台功能让我们离在 Web 平台上实现流畅的进入和退出动画又近了一步。如需了解详情,请访问以下链接: