流れ続けるカルーセルの実装、Splide・GSAP・CSSをどう使い分けるか
下記のような流れ続けるカルーセル(スライダー)を実装しようとしたとき、カルーセルのライブラリを使うべきか、GSAPにすべきか、CSSアニメーションだけで済ませるか迷った経験はないでしょうか。私は結構な頻度で迷います。
そこで、自分なりの指針を整理してみることにしました。この記事では自動で流れ続けるカルーセルの個人的な実装方針について書き留めています。
結論
私は実務では以下のように使い分けることが多いです。
- ユーザーのアクションが入る場合:カルーセルライブラリ(Splide)
- スクロールに連動して動かす場合:アニメーションライブラリ(GSAP)
- 上記以外:CSSアニメーション
表にまとめると次のようになります。
| Splide | GSAP | CSSアニメーション | |
|---|---|---|---|
| 適している例 | スワイプ・ページ送り・一時停止などのユーザー操作がある | スクロールに連動して速度・方向等が変わる | シンプルな自動スクロール、斜め方向など |
それぞれの実装パターンについて個別に見ていきます。
カルーセルライブラリを使用するケース
今回はSplideを使用しました。
npmでインストールするか、下記のようにCDNからファイルを参照します。
<script src="https://cdn.jsdelivr.net/npm/@splidejs/splide@4.1.4/dist/js/splide.min.js"></script><link href="https://cdn.jsdelivr.net/npm/@splidejs/splide@4.1.4/dist/css/splide-core.min.css" rel="stylesheet">今回のような自動スクロールを導入する場合にはAuto Scrollのエクステンションが必要です。
<script src="https://cdn.jsdelivr.net/npm/@splidejs/splide-extension-auto-scroll@0.5.3/dist/js/splide-extension-auto-scroll.min.js"></script>下記が実装例です。
カルーセルライブラリで導入したスライダーの特徴としては、ユーザー操作の実装をスムーズに行える点です。上記の例では左右にスワイプができ、「前へ」「次へ」のページ送りのボタンが機能するようにオプションを設定しています。
const options = { type: "loop", autoWidth: true, gap: "10px", pagination: false, arrows: true, // 前へ・次へのページ送りを表示するかどうか(デフォルトでture) drag: true, // ドラッグによりスライダーを動かせるかどうか(デフォルトでture) autoScroll: { speed: 0.7, pauseOnFocus: false, pauseOnHover: false, },};Splideではアクセシビリティについても一定程度担保してくれるのが良い点です。
デメリットとしては、ライブラリの仕様に縛られるため、複雑なカスタマイズを行おうとするとコストがかかります。またカスタマイズによっては実装困難な場合があります。
例えばSplideでは斜め方向に自動スクロールさせようとtransform: rotate(45deg);を記述すると、表示が崩れます。これはSplideが内部でtransformを使ってスライドの位置を制御しているため、外側からrotateを重ねると競合してしまうためです(Swiperでは問題なさそうでした)。
メリット・デメリットをまとめると次のようになります。
| メリット | デメリット |
|---|---|
|
|
実際の使用例としては、採用ページによくある「数字で見るXXX」をカード形式のスライドとして見せる場合に、カルーセルライブラリを使用するようにしています。
アニメーションライブラリを使用するケース
次にアニメーションライブラリを使用するケースです。今回はGSAPを使用しました。
こちらもnpmでインストールするか、下記のようにCDNからファイルを参照します。後ほどスクロールに連動した動きを実装するため、ScrollTriggerも読み込んでいます。
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/gsap.min.js"></script><script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/ScrollTrigger.min.js"></script>まずはシンプルな流れ続けるカルーセルを実装しました。
GSAPの特徴としてはとても少ない量のコードで実装できる点があります。上記の例ではわずか7行のJavaScriptのコードで動いています。
const lists = gsap.utils.toArray('[data-infinite-carousel="list"]');
const loop = gsap.to(lists, { xPercent: -100, ease: "none", duration: 30, repeat: -1,});そしてGSAPが得意なスクロール連動の動きも実装することができます。次の例ではスクロールの速度(強度)に応じて、スライダーの動く速度も早くなるように実装しています。
近年のWebサイトでよく見かける動きですよね。他にスクロールの方向に応じてスライドが移動する向きを反転させる動きも見かけることが多いです。
GSAPでカルーセルを実装するデメリットとしては、ドラッグ操作やページ送りなどのユーザー操作には不向きな点です。GSAPはあくまでもアニメーションに関する動きを制御するだけなので、ユーザー操作を実現するには全て自前で実装する必要があります。
メリット・デメリットをまとめると次のようになります。
| メリット | デメリット |
|---|---|
|
|
スクロール連動やリッチな動きが求められる場合は、GSAPで実装するのが最も適しています。
CSSアニメーションを使用するケース
最後にCSSアニメーションを使用するケースです。HTMLとCSSのみで完結するため、ライブラリを読み込む必要はありません。下記が実装例です。
最大のメリットはコード量が少なくシンプルなことでしょう。画像(スライド)のリストを横並びにし、translateが変化する@keyframesを設定するのみで機能します。
.c-infinite-carousel { display: flex; overflow: hidden;}
.c-infinite-carousel__list { display: flex; animation: infinity-scroll-from-left 30s infinite linear;}
@keyframes infinity-scroll-from-left { from { transform: translateX(0); } to { transform: translateX(-100%); }}画像(スライド)のリストをtranslateで移動させているだけなので、次のような斜め方向への無限スクロールも簡単に実装できます。以下はtransform: rotate(-20deg);を設定した作例です。
デメリットとしてはリストの境目で、カクつきが発生しやすいことです。特に要素間の余白をcolumn-gapで設定しているとカクつきが発生しやすい印象です。
column-gapでカクつきが発生しやすい理由は、translateX(-100%)の基準となる幅の計算にあります。translateX(-100%)はその要素自身の幅を基準に移動量を計算しますが、column-gapで設定した余白はその幅に含まれません。そのため、アニメーションがループして最初の位置に戻る際に、余白分だけ位置がずれてカクつきが発生します。
一方でmarginで余白を設定した場合は、余白を含めた位置の計算がtranslateX(-100%)と一致しやすくなるため、ループ時のずれが発生しにくくなります。
/*カクつきが発生しやすいコード例*/.c-infinite-carousel { display: flex; overflow: hidden; /* column-gapでリスト間の余白を設定 */ column-gap: 10px;}
.c-infinite-carousel__list { display: flex; /* column-gapでスライド間の余白を設定 */ column-gap: 10px; animation: infinity-scroll-from-left 30s infinite linear;}
.c-infinite-carousel__item { width: 200px; aspect-ratio: 1;}
/*カクつきを抑えたコード例*/.c-infinite-carousel { display: flex; overflow: hidden;}
.c-infinite-carousel__list { display: flex; animation: infinity-scroll-from-left 30s infinite linear;}
.c-infinite-carousel__item { /* margin-leftで余白を設定 */ margin-left: 10px; width: 200px; aspect-ratio: 1;}メリット・デメリットをまとめると次のようになります。
| メリット | デメリット |
|---|---|
|
|
近年登場したCSS カルーセル機能を使用すれば、一般的なユーザー操作についてはCSSのみで実装することも可能なようです。ただし未実装のブラウザもあるため、実務で使用するにはまだ先になりそうです。
まとめ
流れ続けるカルーセルの実装方法を3パターン見てきました。それぞれ適しているケースが異なるため、仕様が決まった段階で実装方法を選べると、無駄な手戻りを減らせると感じています。
今回は「流れ続けるカルーセル」に絞った話でしたが、カルーセル以外のUIコンポーネントについても同様に自分なりの判断基準を整理していきたいと思っています。
