流れ続けるカルーセルの実装、Splide・GSAP・CSSをどう使い分けるか

下記のような流れ続けるカルーセル(スライダー)を実装しようとしたとき、カルーセルのライブラリを使うべきか、GSAPにすべきか、CSSアニメーションだけで済ませるか迷った経験はないでしょうか。私は結構な頻度で迷います。

流れ続けるカルーセル

過去にはこのような経験もありました。

  • GSAPで実装したが、後からスワイプ操作が必要になり、カルーセルライブラリに乗り換えた
  • CSSアニメーションで実装したが、カクつきが発生し修正に時間がかかった

そこで、自分なりの指針を整理してみることにしました。この記事では自動で流れ続けるカルーセルの個人的な実装方針について書き留めています。

結論

私は実務では以下のように使い分けることが多いです。

  • ユーザーのアクションが入る場合:カルーセルライブラリ(Splide)
  • スクロールに連動して動かす場合:アニメーションライブラリ(GSAP)
  • 上記以外:CSSアニメーション

表にまとめると次のようになります。

SplideGSAPCSSアニメーション
適している例スワイプ・ページ送りなどのユーザー操作があるスクロールに連動して速度・方向等が変わるシンプルな自動スクロール、斜め方向など
導入コスト本体+拡張(約30KB)本体+ScrollTrigger(約30KB)ライブラリ不要
アニメーションの自由度ライブラリの仕様に依存高い中程度(複雑な制御は困難)
アクセシビリティライブラリが一定程度カバー自前で対応が必要自前で対応が必要

それぞれの実装パターンについて個別に見ていきます。

カルーセルライブラリを使用するケース

今回はSplideを使用しました。

自動スクロールを導入する場合にはAuto Scrollのエクステンションが必要です。下記が実装例です。

Splideで実装した流れ続けるカルーセル

カルーセルライブラリで導入したスライダーの特徴としては、ユーザー操作の実装をスムーズに行える点です。上記の例では左右にスワイプができ、「前へ」「次へ」のページ送りのボタンが機能するようにオプションを設定しています。

オプションの設定例
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を使用しました。

まずはシンプルな流れ続けるカルーセルを実装した例です。

GSAPで実装した流れ続けるカルーセル

GSAPの特徴としてはとても少ない量のコードで実装できる点があります。上記の例ではわずか7行のJavaScriptのコードで動いています。

script.js
const lists = gsap.utils.toArray('[data-infinite-carousel="list"]');
const loop = gsap.to(lists, {
xPercent: -100,
ease: "none",
duration: 30,
repeat: -1,
});

そしてGSAPが得意なスクロール連動の動きも実装することができます。

次の例ではスクロールの速度(強度)に応じて、スライダーの動く速度も早くなるようにしています。スクロールに連動した動きを実装するため、ScrollTriggerを読み込んでいます。

スクロール速度に応じて移動スピードが変わるカルーセル

近年のWebサイトでよく見かける動きですよね。他にスクロールの方向に応じてスライドが移動する向きを反転させる動きを実装することも可能です。

GSAPでカルーセルを実装するデメリットとしては、ドラッグ操作やページ送りなどのユーザー操作には不向きな点です。GSAPはあくまでもアニメーションに関する動きを制御するだけなので、ユーザー操作を実現するには全て自前で実装する必要があります。

メリット・デメリットをまとめると次のようになります。

メリットデメリット
  • スクロールに連動したアニメーションを容易に実装できる
  • 柔軟にアニメーションをカスタマイズできる
  • ライブラリを読み込む必要がある
  • ユーザー操作は自前で実装する必要がある

スクロール連動やリッチな動きが求められる場合は、GSAPで実装するのが最も適しています。

CSSアニメーションを使用するケース

最後にCSSアニメーションを使用するケースです。HTMLとCSSのみで完結するため、ライブラリを読み込む必要はありません。下記が実装例です。

CSSで実装した流れ続けるカルーセル

最大のメリットはコード量が少なくシンプルなことでしょう。画像(スライド)のリストを横並びにし、translateが変化する@keyframesを設定するのみで機能します。

style.css
.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);を設定した例です。

CSSで実装した斜め方向に流れ続けるカルーセル

デメリットとしてはリストの境目で、カクつきが発生しやすいことです。特に要素間の余白をcolumn-gapで設定しているとカクつきが発生しやすい印象です。

column-gapでカクつきが発生しやすい理由は、translateX(-100%)の基準となる幅の計算にあります。translateX(-100%)はその要素自身の幅を基準に移動量を計算しますが、column-gapで設定した余白はその幅に含まれません。そのため、アニメーションがループして最初の位置に戻る際に、余白分だけ位置がずれてカクつきが発生します。

一方でmarginで余白を設定した場合は、余白を含めた位置の計算がtranslateX(-100%)と一致しやすくなるため、ループ時のずれが発生しにくくなります。

style.css
/*
カクつきが発生しやすいコード例
*/
.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;
}

メリット・デメリットをまとめると次のようになります。

メリットデメリット
  • HTMLとCSSのみで完結でき管理が容易
  • JavaScriptライブラリが不要で軽量
  • 斜め方向の動きにも対応できる
  • カクつきが発生することがある
  • 複雑な動きに対応しようとするとCSSのみでは困難

近年登場したCSS カルーセル機能を使用すれば、一般的なユーザー操作についてはCSSのみで実装することも可能なようです。ただし未実装のブラウザもあるため、実務で使用するにはまだ先になりそうです。

prefers-reduced-motionへの対応

流れ続けるカルーセルは自動で動き続けるため、OSで「視差効果を減らす」が有効な環境への配慮が必要です。どの手法を選んでも、アニメーションを停止する対応を入れておくと安心です。

Splideの場合はreducedMotionオプションが用意されており、autoScroll: falseを設定することで自動スクロールを停止できます。

const options = {
// ...省略
// (prefers-reduced-motion: reduce)を検出した際に使用されるオプション
reducedMotion: {
autoScroll: false,
},
};

GSAPの場合はgsap.matchMedia()を使用して分岐できます。

const mm = gsap.matchMedia();
// 視差効果を減らす設定がされていない環境でのみ実行
mm.add("(prefers-reduced-motion: no-preference)", () => {
gsap.to(lists, {
xPercent: -100,
ease: "none",
duration: 30,
repeat: -1,
});
});

CSSアニメーションの場合は、先述のコード例に以下のメディアクエリを追加することで対応できます。

.c-infinite-carousel__list {
display: flex;
/* 視差効果を減らす設定がされていない環境でのみ実行 */
@media (prefers-reduced-motion: no-preference) {
animation: infinity-scroll-from-left 30s infinite linear;
}
}

停止ではなくスクロール速度を落とすだけにする考え方もありますが、中途半端な動きがかえって違和感を生むケースがあるため、停止で統一しています。

まとめ

流れ続けるカルーセルの実装方法を3パターン見てきました。それぞれ適しているケースが異なるため、仕様が決まった段階で実装方法を選べると、無駄な手戻りを減らせると感じています。

今回は「流れ続けるカルーセル」に絞った話でしたが、カルーセル以外のUIコンポーネントについても同様に自分なりの判断基準を整理していきたいと思っています。

この記事を書いた人

写真:ブール 代表 西川雅人

Masato Nishikawa

ウェブ制作会社・デザイナー様向けに、コーディングやWordPress実装を承っているフリーランスです。繁忙期のサポートや、継続的な外注先をお探しでしたら、お気軽にお声がけください。

コーディングや
WordPress実装の
ご相談を承っています。

新規制作から運用フェーズの修正まで柔軟に対応します。
お見積りや実装可否の確認など、お気軽にご連絡ください。