群組元素轉場效果

在清單中新增、移除或重新排列項目時,轉場效果可協助使用者掌握背景資訊。檢視畫面轉換可為元素提供不重複的 view-transition-name,在元素的兩種狀態之間轉換。當頁面上的多個元素共用相同的轉場行為時,view-transition-class 可讓您在 CSS 中定義該邏輯一次,而不必為每個不重複的 view-transition-name 重複定義。這樣一來,樣式表不僅容易維護,還能確保一組元素的動畫效果一致。

導入步驟

  1. 指派不重複的名稱和共用類別

    在轉場期間,每個需要個別追蹤的元素都必須有專屬的 view-transition-name。

    <!-- Mandatory: Each element must have a unique view-transition-name -->
    <li style="view-transition-name: item-1" class="item">Item 1</li>
    <li style="view-transition-name: item-2" class="item">Item 2</li>
    

    如要套用共用樣式,請一併指派 view-transition-class。

    .item {
      view-transition-class: list-item;
    }
    
  2. 定義共用轉場邏輯

    使用 ::view-transition-group() 虛擬元素和類別選取器,將樣式套用至該群組的所有成員。

    /* Targets any view transition group that has the 'list-item' class */
    ::view-transition-group(.list-item) {
      animation-duration: 0.5s;
      animation-timing-function: ease-in-out;
    }
    
    /* Handle accessibility by respecting motion preferences */
    @media (prefers-reduced-motion: reduce) {
      /* Disable all group transitions, including the default `root` group. */
      ::view-transition-group(*),
      ::view-transition-old(*),
      ::view-transition-new(*) {
        animation: none !important;
      }
    }
    
  3. 選用:定義進場和退場動畫

    使用 :only-child 選取器,為新增或移除的元素加入特定轉場效果。::view-transition-new() 和 ::view-transition-old() 虛擬元素是 ::view-transition-image-pair() 虛擬元素的子項,因此如果它是唯一的子項,我們就能判斷它是新增或移除的元素。

    /* A `::view-transition-new()` element is the only child if it wasn't present before the view transition, so it is an added element. */
    ::view-transition-new(.list-item):only-child {
      animation-name: slide-in;
      /* Specify an animation duration if you want something different than the UA default of 0.5s */
      animation-duration: 1s;
    }
    /* A `::view-transition-old()` element is the only child if it isn't present after the view transition, so it is a removed element. */
    ::view-transition-old(.list-item):only-child {
      animation-name: slide-out;
      /* Specify an animation duration if you want something different than the UA default of 0.5s */
      animation-duration: 1s;
    }
    
    @keyframes slide-in {
      from {
        translate: -100vw 0;
      }
    }
    @keyframes slide-out {
      to {
        translate: -100vw 0;
      }
    }
    
  4. 觸發轉換

    將 DOM 更新包裝在 document.startViewTransition() 中。瀏覽器會擷取舊狀態、執行更新,然後以動畫形式呈現新狀態。

    function updateList(newData) {
      document.startViewTransition(() => {
        // All DOM changes inside this callback will be transitioned
        render(newData);
      });
    }
    
  5. 維持非轉換元素的互動性

檢視畫面轉換的運作方式是疊加 DOM 元素的快照,然後轉換快照。這表示在轉換期間,元素無法互動。如果有未轉換的互動元素,可以停用檢視畫面轉換的觸控事件,讓這些元素可供互動。

::view-transition {
  /* Non-transitioned elements below the view transitions remain interactive */
  pointer-events: none;
}

此外,:root 元素預設具有名為 root 的檢視畫面轉場效果,可啟用預設的全頁轉場效果。如果根元素沒有任何變更,這會是兩個相同快照之間的轉場效果,無法互動。由於我們只轉換特定元素,而非整個畫面,因此可以停用 root 轉換。

:root {
  /* Disable the root transition because we are only transitioning specific elements. */
  view-transition-name: none;
}

備用策略

View Transitions 是一種漸進增強功能。如果瀏覽器不支援 document.startViewTransition,DOM 更新仍應立即執行,提供功能正常但沒有動畫的效果。

if (document.startViewTransition) {
  document.startViewTransition(() => updateDOM());
} else {
  // Fallback: Perform the update without animation
  updateDOM();
}

如果是 CSS,無法辨識 view-transition-class 或 ::view-transition-group() 類別選取器的瀏覽器會直接忽略這些規則,不會套用任何動畫。