グループ要素の遷移

リストにアイテムが追加または削除されたり、並べ替えられたりしたときに、遷移を使用すると、ユーザーがコンテキストを維持しやすくなります。ビュー遷移では、要素に一意の view-transition-name を指定することで、要素の 2 つの状態間を遷移できます。ページ上の複数の要素が同じ遷移動作を共有する場合、view-transition-class を使用すると、一意の view-transition-name ごとに繰り返すのではなく、CSS でそのロジックを 1 回定義できます。これにより、スタイルシートの保守性を維持しながら、要素のグループ全体で一貫したアニメーションを実現できます。

実装の手順

  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 というビュー遷移があり、デフォルトのフルページ遷移が有効になっています。ルート要素に変更がない場合、これは 2 つの同一のスナップショット間の遷移となり、インタラクティブではありません。画面全体ではなく特定の要素のみを移行するため、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() クラス セレクタを認識しないブラウザでは、これらのルールが無視され、アニメーションは適用されません。