ウェブ制作ではカルーセル(スライドショーとも呼びます)はよく利用されるユーザーインターフェイスです。複数のバナーをスペースを節約してレイアウトできるので、情報を整理しやすく、訴求しやすいといった利点があります。
カルーセルをウェブで実装するにはJavaScriptが欠かせませんが、自力でゼロから実装すると想像以上に大変なものです。そのため、JavaScriptライブラリを採用することが制作現場では多いです。数多くのJSライブラリが存在しますが、著者がピックアップした3種類のライブラリを比較紹介します。
紹介するJSライブラリ
次の3種類のライブラリを紹介します。
それぞれのJSライブラリについて、ファイルサイズやTypeScriptのサポート状況などを比較表としてまとめました。
Slick.js | Swiper.js | keen-slider.js | |
---|---|---|---|
ファイルサイズ | 約52KB | 約146KB | 10KB |
依存ライブラリ | jQuery | Dom7 (内部で使用) |
- |
CDN | ◯ | ◯ | ◯ |
npm | ◯ | ◯ | ◯ |
TypeScriptのサポート | 非公式 | ◯ | ◯ |
React, Vue, Angular | 非公式 | ◯ | ◯ |
a11yのサポート | ◯ | ◯ | - |
ナビゲーション (前後へスライドするボタンなど) |
◯ | ◯ | - |
いずれもMITライセンスで公開されていますので、個人・商用問わず利用可能です。
Slick.js
Slick.jsは簡潔なコードで実装できるのが特徴のモバイルフレンドリーなカルーセルライブラリです。機能は少なめですが、ナビゲーションや表示するスライド数を変更するといった基本的な機能は備わっています。jQueryプラグインのため実装にはjQueryを読み込む必要があります。タッチ・スワイプ操作にも対応しています。ReactやVue向けのモジュール、TypeScriptのサポートは公式で提供されていませんがOSSで存在します。
このJSライブラリの基本的な実装と、アニメーションをフェードに変えた作例を用意しました。
基本の作例
<div class="slick carousel">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
$(document).ready(() => {
$(".slick").slick({
infinite: true, // ループの有効化
dots: true, // ドットインジケーターの表示
});
});
アニメーションをフェードに変えた作例
アニメーションをフェードに切り替えたい場合は、fade
プロパティを有効化します。有効化すると、スワイプ中にアニメーションが発生しなくなるため注意が必要です。
(上述の作例とHTMLコードは同じ)
$(document).ready(() => {
$(".slick").slick({
infinite: true, // ループの有効化
dots: true, // ドットインジケーターの表示
fade: true, // フェードアニメーションを有効化
});
});
Swiper.js
Swiper.jsはタッチパネルのデバイスで使われることを重点においているカルーセルライブラリです。Slick.jsと同様に、タッチ・スワイプ操作にも対応しています。エフェクトモジュールを使用して、簡単に多彩な表現ができるのが大きな特徴です。機能が豊富なため容量も大きいですが、ES Modulesのimport文でモジュールを絞ったインポートができるので工夫次第で容量を節約できます。
多くのイベントが準備されているため、さまざまな表現に柔軟に対応できます。今も更新が頻繁に行われているためバージョンアップのサイクルが早いことも特徴です。
依存ライブラリについては、同じ作者が開発されているDom7というJSライブラリが使われていますが、Swiper.jsに内蔵されているためとくに意識する必要はありません。
このJSライブラリの基本的な実装と、エフェクトモジュールを利用した作例をいくつか用意しました。
基本の作例
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide">
<div>1</div>
</div>
<div class="swiper-slide">
<div>2</div>
</div>
<div class="swiper-slide">
<div>3</div>
</div>
</div>
<div class="swiper-pagination"></div>
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
const swiper = new Swiper(".swiper-container", {
// ドットインジケーターの表示
pagination: {
el: ".swiper-pagination",
},
// 前後スライドボタンを表示
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev",
},
loop: true, // ループの有効化
});
フェードエフェクトを使用した作例
(上述の作例とHTMLコードは同じ)
const swiper = new Swiper(".swiper-container", {
/* ドットインジケーター、前後ボタン、ループの記述は省略 */
effect: "fade",
fadeEffect: {
crossFade: true
},
});
カバーフローエフェクトを使用した作例
(上述の作例とHTMLコードは同じ)
const swiper = new Swiper(".swiper-container", {
/* ドットインジケーター、前後ボタン、ループの記述は省略 */
slidesPerView: 1.6, // 表示するスライドの枚数
centeredSlides : true, // スライドを中央揃えを有効化
effect: "coverflow",
coverflowEffect: {
rotate: 0, // スライドの回転角度
stretch: 50, // スライドの間隔(px単位)
depth: 200, // 奥行きの設定(translateをZ方向にpx単位で移動)
modifier: 1, //
slideShadows : true, // 先頭スライドのbox-shadowを有効化
},
});
カードエフェクトを使用した作例
(上述の作例とHTMLコードは同じ)
const swiper = new Swiper(".swiper-container", {
/* ドットインジケーター、前後ボタン、ループの記述は省略 */
grabCursor: true,
effect: "cards",
});
クリエイティブエフェクトを使用した作例
クリエイティブエフェクトは表示しているスライドの移動先と、次に表示されるスライドのCSSプロパティをいくつか操作できます。このサンプルでは、前後のスライドがアニメーションされる時のtransform: translate()
を操作しています。
(上述の作例とHTMLコードは同じ)
const swiper = new Swiper(".swiper-container", {
/* ドットインジケーター、前後ボタン、ループの記述は省略 */
grabCursor: true,
effect: "creative",
creativeEffect: {
prev: { // 表示しているスライドの移動先
shadow: true, // 影の有効化
translate: [0, 0, -400], // translateをX,Y,Zで指定
},
next: { // 次に表示されるスライドの設定
translate: ["100%", 0, 0], // translateをX,Y,Zで指定
},
},
});
keen-slider.js
keen-slider.jsはカスタマイズが前提とされているシンプルなカルーセルライブラリです。カルーセルを実装するために必要なコアな機能が用意されていて、Slick.jsやSwiper.js同様にタッチ・スワイプ操作にも対応しています。よくある機能の実装方法については公式ドキュメントで作例が紹介されています。
機能が豊富なJSライブラリは便利なことも多いですが、ウェブサイトの要件次第でライブラリ自体のデフォルト挙動が不都合になる場合があります。このライブラリではコアな役割はライブラリにまかせつつ、必要な機能はライブラリの挙動になるべく干渉せず実装できます。
このJSライブラリの基本的な作例を用意しました。ドットのインジケーターや前後へのスライドボタンなど、必要な機能はイベントやメソッドを利用して実装しています。
基本の作例
<div class="keen-slider carousel">
<div class="keen-slider__slide">
<div class="carousel-item carousel-item__bgcBlue">1</div>
</div>
<div class="keen-slider__slide">
<div class="carousel-item carousel-item__bgcYellow">2</div>
</div>
<div class="keen-slider__slide">
<div class="carousel-item carousel-item__bgcRed">3</div>
</div>
</div>
<div id="arrow-left" class="arrow arrow--left">
<img src="./assets/arrow-left.svg" alt="">
</div>
<div id="arrow-right" class="arrow arrow--right">
<img src="./assets/arrow-right.svg" alt="">
</div>
<div id="dots" class="dots"></div>
const keenSlider = new KeenSlider(".keen-slider", {
loop: true,
created: (instance) => { // はじめて初期化された後に実行
// 左の矢印ボタンをクリックしたら1つ前のスライドに移動
document
.getElementById("arrow-left")
.addEventListener("click", () => {
instance.prev();
});
// 右の矢印ボタンをクリックしたら1つ先のスライドに移動
document
.getElementById("arrow-right")
.addEventListener("click", () => {
instance.next();
});
// ドットインジケーターを生成する親要素を取得
const dots_wrapper = document.getElementById("dots");
// スライドと同じ数のドットインジケーターを生成
const slides = document.querySelectorAll(".keen-slider__slide");
slides.forEach((t, idx) => {
const dot = document.createElement("button");
dot.classList.add("dot");
dots_wrapper.appendChild(dot);
// ドットインジケーターをクリックしたら同じ列番号のスライドへ移動
dot.addEventListener("click", () => {
instance.moveToSlide(idx);
});
});
// CSSクラスの更新
updateClasses(instance);
},
slideChanged: (instance) => { // 現在表示されているスライドが変更された時に実行
// CSSクラスの更新
updateClasses(instance);
},
})
/**
* 各要素のCSSクラスを更新
* @param instance
*/
function updateClasses(instance) {
// 現在表示しているスライドの列番号を取得
const slide = instance.details().relativeSlide;
// 前後にスライドする矢印ボタンの状態を更新
const arrowLeft = document.getElementById("arrow-left");
const arrowRight = document.getElementById("arrow-right");
slide === 0 // 最初のスライドの場合
? arrowLeft.classList.add("arrow--disabled")
: arrowLeft.classList.remove("arrow--disabled");
slide === instance.details().size - 1 // 最後のスライドの場合
? arrowRight.classList.add("arrow--disabled")
: arrowRight.classList.remove("arrow--disabled");
// 生成されたドットインジケーターの要素を取得し状態を更新
const dots = document.querySelectorAll(".dot");
dots.forEach((dot, idx) => {
idx === slide
? dot.classList.add("dot--active")
: dot.classList.remove("dot--active");
})
}
わかりやすいカルーセルを心がけよう
カルーセルは便利なユーザーインターフェイスですが、はじめに表示されているスライド以外はユーザーに気づかれにくいといったデメリットも存在します。
今回紹介したほとんどのサンプルは、次のスライドが存在していることが視覚的にわかりにくいため、ユーザーインターフェイスであることに気づかれない可能性があります。Swiper.jsで紹介したカバーフローのサンプルのように次のスライドを一部表示させるなど、効果的に使うためにはカルーセルの特徴をおさえておく必要があるでしょう。
まとめ
自力でゼロから実装すると大変なカルーセルですが、ライブラリを使用することで手軽に実装できます。基本的な機能はどのライブラリも似ているところがありますが、少し踏み込むとそれぞれの特徴あるので目的に合わせて選びましょう。
紹介したライブラリの中から選ぶ場合は、以下の判断基準を参考にしてみてください。
- 高機能で多彩な表現を使用したい場合はSwiper.js
- jQueryを使用しているプロジェクトや、Swiper.jsほど機能を必要としない場合はSlick.js
- 独自の機能や演出を取り入れたい場合はkeen-slider.js