動態

  • 使用 clip-path 和 mask-image,自訂幾何圖形顯示和流暢淡出效果。
  • 使用捲動驅動動畫 (animation-timeline: scroll()) 處理非必要的捲動效果,而非 JS 事件監聽器。
  • 使用檢視畫面轉換,在複雜的版面配置狀態之間順暢切換動畫。

效能

  • 建議您為 opacity 和 transform 加上動畫效果 (包括個別轉換屬性,例如 translate,而非 left/right/top/bottom),確保動畫保留在合成器執行緒上。
  • 使用 transition-behavior: allow-discrete、@starting-style 和 (適用於 <dialog> 或 [popover] 等頂層元素) overlay,以原生方式為離散的進入和退出狀態建立動畫;請參閱「為元素進入和退出建立動畫」和「為元素進出頂層建立動畫」。
.popover-reveal {
  /* Transition discrete display and top-layer overlay alongside opacity */
  transition:
    opacity ease-out,
    display,
    overlay;
  transition-duration: 0.2s;
  transition-behavior: allow-discrete;
}

無障礙設定

使用 prefers-reduced-motion 媒體查詢,為偏好減少動態效果的使用者關閉大幅度動態效果。

  • 提供暫停機制:允許使用者停止自動執行的輪轉介面、橫幅或其他持續動畫。
  • 預設為靜態檢視畫面:建議預設為靜態狀態,並允許使用者選擇加入動態效果。
  • 閃爍頻率不得超過上限 (每秒三次):請勿使用快速明暗閃爍效果。這類效果可能會導致癲癇發作。

請勿全面套用 animation-duration: 0.01ms;,因為這可能會導致某些動畫變得「更」不協調。請改用下列兩種方法之一,逐一處理動態偏好設定,將 @media 查詢嵌入規則中,以便同時保留兩個版本:

  • 預設啟用動畫,並使用 @media (prefers-reduced-motion: reduce) 降低動畫效果:
/* Good: Dampen spin states or slow down animations for reduced motion */
.spinner {
  animation: spin 1s linear infinite;
  @media (prefers-reduced-motion: reduce) {
    animation: none;
    opacity: 0.5;
  }
}

progress:not([value]) {
  animation: slide 1s infinite linear;
  @media (prefers-reduced-motion: reduce) {
    animation-duration: 20s;
  }
}
  • 預設不啟用動畫,並使用 @media (prefers-reduced-motion: no-preference) 啟用動畫:
/* Good: Default to static or gentle states and opt-in to full motion */
.spinner {
  opacity: 0.5;
  @media (prefers-reduced-motion: no-preference) {
    opacity: 1;
    animation: spin 1s linear infinite;
  }
}

progress:not([value]) {
  animation: slide 20s infinite linear;
  @media (prefers-reduced-motion: no-preference) {
    animation-duration: 1s;
  }
}

在 JavaScript 中使用動畫和轉場事件

在 AnimationEvent (animationstart、animationiteration、animationend、animationcancel) 和 TransitionEvent (transitionrun、transitionstart、transitionend、transitioncancel) 介面上,event.target 會提供原始 DOM 元素。如要存取觸發事件的特定 Animation 物件 (Animation、CSSAnimation 或 CSSTransition),請使用唯讀 event.animation 屬性。

如果無法使用 event.animation,通常可以呼叫 event.target.getAnimations() 並依 event.animationName (或 event.propertyName 進行轉換) 篩選,找出 Animation 執行個體。不過,建議您直接使用 event.animation,以免篩選 event.target.getAnimations() 的備用機制在某些情況下無法正常運作:

  • Web Animations API (element.animate()) 動畫沒有 animationName,因此篩選 event.target.getAnimations() 時無法依名稱比對。
  • 如果多個同名動畫附加至同一個元素,則依 animationName 篩選 AnimationEvent 會造成混淆。
    • 請注意,由於每個轉換屬性只有一個事件,因此篩選 TransitionEvent 的 transitionProperty 適用。
  • event.target 一律指向原始 DOM 元素,因此不會區分在元素本身執行的動畫和在其中一個虛擬元素執行的動畫,而 event.animation.effect.pseudoElement 則會直接公開目標虛擬元素。
// Works in most basic CSS animation cases, but fails for WAAPI animations,
// duplicate animation names on the same element, or pseudo-elements.
document.addEventListener('animationstart', (event) => {
  const animation = event.target
    .getAnimations()
    .find((anim) => anim.animationName === event.animationName);
  console.log(animation);
});

// PREFERRED: Directly access the exact Animation object via event.animation
document.addEventListener('animationstart', (event) => {
  const animation = event.animation;
  console.log(animation);
});

您可以使用 'animation' in AnimationEvent.prototype (或 'animation' in TransitionEvent.prototype) 偵測功能支援。