カルーセル スライド エフェクトを作成する

カルーセルのスライド効果は、カルーセルに視覚的な魅力を加える優れた方法です。ユーザーがスライドをスクロールすると、各スライドがスクロールポートに入り、中央に移動し、終了する際にアニメーション化されます。たとえば、スライドをフェードイン / フェードアウトしたり、回転させたり、サイズを拡大 / 縮小したりできます。これにより、動的で魅力的なユーザー エクスペリエンスが実現します。単純なエントリ / 終了アニメーションとは異なり、この効果では、1 つの連続したアニメーションを使用して、スクロールポート全体でスライドの表示を制御します。

導入方法

カルーセルのスライド効果を作成する方法は次のとおりです。

  1. スクローラーを作成する: この要素は、カルーセル スライドのコンテナとして機能します。この例では、overflow-x: scroll を使用して水平スクロールを可能にしています。

    <ul class="scroller">
      <li class="entry">1</li>
      <li class="entry">2</li>
      <li class="entry">3</li>
      …
    </ul>
    
    .scroller {
      overflow-x: scroll;
    }
    
  2. アニメーションを定義する: スライドがスクロールポートを通過する際の状態を定義する CSS アニメーションを作成します。キーフレームは、アニメーションのどの部分にも定義できます。たとえば、50% キーフレームを含めることで、スライドがスクロールポートの中央にあるときの状態を定義できます。この例では、scale プロパティにより、スライドが中央に近づくにつれて大きくなり、離れるにつれて小さくなります。

    @keyframes animate {
      0% {
        scale: 0.5;
      }
      50% {
        scale: 1;
      }
      100% {
        scale: 0.5;
      }
    }
    
  3. アニメーションと view-timeline を適用する: アニメーションをカルーセル スライドに適用し、コンテナをスクロールする要素を追跡する view-timeline にリンクします。

    .scroller > * {
      animation: animate auto linear both;
      animation-timeline: view(inline);
    }
    

    デフォルトでは、view() は block 軸上の要素をトラッキングします。inline 軸でトラッキングする必要がある場合は、view(inline) を使用できます。

コード例

このコードは、匿名のビュー タイムラインを使用して、スクロール時に水平スクローラーのカルーセル アイテムをアニメーション化します。

@keyframes animate {
  0% {
    scale: 0.5;
  }

  50% {
    scale: 1;
  }

  100% {
    scale: 0.5;
  }
}

.scroller > * {
  /* Applies the animation using an `auto` duration */
  animation: animate auto linear both;
  /* Sets the animation timeline to use an anonymous view progress timeline, tracking the element's progress through the scroller on the inline axis */
  animation-timeline: view(inline);
}

このコードは、名前付きの view-timeline を使用して、スクロール時に水平スクローラーのカルーセル アイテムをアニメーション化します。

@keyframes animate {
  0% {
    scale: 0.5;
  }

  50% {
    scale: 1;
  }

  100% {
    scale: 0.5;
  }
}

/* This creates a named view-timeline on each carousel item. The timeline is used to drive the animation that is applied on the same element. */
.scroller > * {
  /* Applies the animation using an `auto` duration */
  animation: animate auto linear both;
  /* Defines a named view progress timeline, tracking the element's progress through the scroller on the inline axis */
  view-timeline: --item inline;
  /* Sets the animation timeline to use the named view progress timeline defined above */
  animation-timeline: --item;
}

ベスト プラクティス

スクロール駆動型アニメーションを使用する場合は、スムーズでアクセスしやすいエクスペリエンスを実現するために、いくつかのベスト プラクティスに従うことが重要です。

  • 推奨: 機能検出を含める。すべてのブラウザがスクロールドリブン アニメーションをサポートしているわけではありません。@supports ((animation-timeline: view()) and (animation-range: entry)) を使用してサポートを確認し、サポートしていないブラウザに代替を提供します。
    • 部分的にしかサポートしていないブラウザを除外するには、ここに (animation-range: entry) チェックを含める必要があります。
    • フォールバック戦略に scroll-timeline-polyfill パッケージを使用しないでください。このパッケージは機能が完全ではなく、既知の問題が多数あります。
    • アニメーションが装飾的なものにすぎない場合は、プログレッシブ エンハンスメントを選択し、代替手段を提供しないでください。
  • 推奨事項: ユーザーの設定を尊重します。ウェブ上でのモーションを好まないユーザーもいます。prefers-reduced-motion メディアクエリを使用して、これらのユーザーに対してアニメーションを無効にするか、アニメーションを減らします。
  • 推奨: パフォーマンスの高い CSS プロパティのみをアニメーション化する。アニメーションを最もスムーズにするには、ブラウザのコンポジタ スレッドで処理できるプロパティ(transform や opacity など)のみをアニメーション化します。width や height などの他のプロパティをアニメーション化すると、パフォーマンスの問題が発生する可能性があります。
  • 推奨: 正しい宣言順序を使用する。animation 略式プロパティを使用する場合は、略式プロパティがタイムラインをリセットしないように、animation-timeline と animation-range をその後に宣言します。

複数の DOM 要素を同じタイムラインに基づいてアニメーション化する必要がある場合や、view-timeline が定義されている要素の子をアニメーション化する必要がある場合は、名前付きの view-timeline を使用することをおすすめします。アニメーション化する要素が view-timeline を定義する要素でもある場合は、view() を使用して匿名の view-timeline を使用できます。

view() 関数を使用してスクロール駆動型アニメーションを作成する場合:

  • 任意: トラッキングする軸を明示的に指定します。デフォルトの block 軸をターゲットにしない場合(水平スクローラーなど)、view(block) または view(inline) でトラッキングする軸を明示的に指定します。

view-timeline プロパティを使用してスクロール駆動型アニメーションを作成する場合:

  • 推奨: 名前には CSS <dashed-ident> を使用します(例: view-timeline: --my-custom-name)。
  • 任意: トラッキングする軸を明示的に指定します。デフォルトの block 軸をターゲットにしない場合(水平スクローラーなど)、view-timeline-axis でトラッキングする軸を明示的に指定します。
  • 推奨: ルックアップのスコープが機能することを確認します。view-timeline を宣言している要素が、アニメーション化された要素のフラットツリーの祖先でない場合は、共有の祖先で timeline-scope を使用して、view-timeline の名前の可視性を引き上げます。

ブラウザのサポートとフォールバック戦略

そのため、通常はフォールバック戦略が必要です。

スクロール駆動型アニメーションをサポートしていないブラウザでは、フォールバックを使用して視覚効果を再現できます。フォールバックは通常、スクロール リスナー(ScrollTimeline 効果の場合)または IntersectionObserver API(ViewTimeline 効果の場合)を使用して構築されます。

スクロールドリブン アニメーションのサポートが組み込まれているブラウザでは、常にネイティブ CSS 実装を使用してください。その方がパフォーマンスが向上します。

フォールバック アプローチを使用してすべてのエフェクトを再現できるわけではありません。

このユースケースでは、次のスクリプトで、スクロール駆動アニメーションをサポートしていないブラウザにフォールバックを適用します。Web Animations API(Element.animate())を使用して、カルーセル内の各アイテムの一時停止アニメーションを作成します。次に、スクローラーの scroll イベントをリッスンし、スクローラー内のアイテムのスクロールの進行状況に基づいて、各アニメーションの currentTime を更新します。

// Fallback for browsers that don't support scroll-driven animations
if (!CSS.supports('(animation-timeline: view()) and (animation-range: entry)')) {
  const scroller = document.querySelector('.scroller');
  const entries = document.querySelectorAll('.entry');

  // Create a map to store animations
  const animations = new Map();

  entries.forEach(entry => {
    const animation = entry.animate(
      {
        scale: ['0.5', '1', '0.5']
      },
      {
        duration: 1, // We'll control the time ourselves
        fill: 'both'
      }
    );
    animation.pause();
    animations.set(entry, animation);
  });

  // Update animations on scroll
  const tick = () => {
    const scrollerRect = scroller.getBoundingClientRect();

    entries.forEach(entry => {
      const animation = animations.get(entry);
      if (!animation) return;

      const entryRect = entry.getBoundingClientRect();
      const progress = (entryRect.left + entryRect.width / 2 - scrollerRect.left) / scrollerRect.width;

      animation.currentTime = progress;
    });
  };
    
  scroller.addEventListener('scroll', tick);
  tick();
}