はじめに
Webサイトを作っていると、カルーセル(スライダー)を実装する場面って意外と多いんですよね。商品一覧、画像ギャラリー、お客様の声など、限られたスペースで複数のコンテンツを見せたいときに便利です。
ただ、カルーセルライブラリって選択肢が多すぎて迷いませんか。Swiper、Slick、Flickityなど有名どころはいくつかありますが、今回紹介するEmbla Carouselは、個人的にかなり気に入っているライブラリです。
軽量で、スワイプの動きが自然で、何より拡張性が高い。37万以上のプロジェクトで使われているという実績もあります。
とはいえ、読むより触った方が早いと思います。ドラッグでスライドを動かせる、実際に動くEmbla Carouselのサンプルを用意しているので、先に挙動を見たい方はこちらからどうぞ。
Embla Carouselの特徴・メリット
軽量で依存関係がない
正直なところ、カルーセルライブラリって重くなりがちなんですよね。でもEmbla Carouselは依存関係がなく、バンドルサイズが小さいのが特徴です。パフォーマンスを気にするプロジェクトでも安心して使えます。
スワイプ精度が高い
モバイルでのスワイプ操作、これ意外と重要なんですよ。安っぽいカルーセルだと、スワイプしたときに「カクッ」となったり、意図しない方向に動いたりすることがあります。
Embla Carouselは「fluid motion and great swipe precision」を謳っているだけあって、スワイプの動きが本当に滑らかです。ユーザー体験がワンランク上がる感じがします。
複数フレームワークに対応
対応しているフレームワークは以下の通りです。
- Vanilla JavaScript / TypeScript
- React
- Vue
- Svelte
- Solid
- CDN(直接読み込み)
Angularについてはコミュニティ製のラッパーがあります。これだけ対応していれば、大抵のプロジェクトで使えますね。
プラグインシステム
Autoplay、ナビゲーションボタン、ドットインジケーターなど、必要な機能をプラグインとして追加できます。必要なものだけ入れられるので、無駄がないんですよね。
活発な開発
GitHub上でスター数7,900以上、1,762のコミット、51名の貢献者がいる活発なプロジェクトです。最新バージョンはv8.6.0(2025年4月リリース)で、継続的にメンテナンスされています。
インストール方法
Vanilla JavaScript / TypeScript
npm install embla-carousel
React
npm install embla-carousel-react
Vue
npm install embla-carousel-vue
Svelte
npm install embla-carousel-svelte
CDN
<script src="https://unpkg.com/embla-carousel/embla-carousel.umd.js"></script>
Embla Carouselのサンプルを動かす
Embla CarouselはEmblaCarousel(node, options)という1つの関数にDOM要素を渡すだけで動き出します。
下のサンプルはスライドを実際に指(またはマウス)でドラッグして動かせるほか、「前へ」「次へ」ボタンでの
操作、loopオプションのON/OFF切り替えにも対応しています。
初期化とAPI呼び出しの要点だけ抜き出すと、次のようになります。
import EmblaCarousel from 'embla-carousel'
const emblaNode = document.querySelector('.embla')
const emblaApi = EmblaCarousel(emblaNode, { loop: true })
// 現在位置が変わるたびに呼ばれる
emblaApi.on('select', () => {
console.log(emblaApi.selectedScrollSnap())
})
// ボタン操作
prevBtn.addEventListener('click', () => emblaApi.scrollPrev())
nextBtn.addEventListener('click', () => emblaApi.scrollNext())
実際に動かせるものが下です。スライドを直接ドラッグしてみてください。スワイプ精度の高さが体感できるはずです。
「loopを無効化」にチェックを入れるとemblaApi.reInit()でオプションを差し替え、端で止まる挙動に変わります。
ボタンを使わずスライドを直接ドラッグしても、マウスでもタッチでも同じ感覚で動く点に注目してください。
emblaApi.on('select', ...)で現在のスライド位置を検知できるので、インジケーターやページネーションの
実装にもそのまま応用できます。
基本的な使い方
HTML構造
まず基本的なHTML構造を理解しておく必要があります。
<div class="embla">
<div class="embla__container">
<div class="embla__slide">スライド 1</div>
<div class="embla__slide">スライド 2</div>
<div class="embla__slide">スライド 3</div>
</div>
</div>
必須のCSS
.embla {
overflow: hidden;
}
.embla__container {
display: flex;
}
.embla__slide {
flex: 0 0 100%;
min-width: 0;
}
この3つのスタイルは必須です。これがないと正しく動作しません。
Vanilla JavaScriptでの実装
import EmblaCarousel from 'embla-carousel'
const emblaNode = document.querySelector('.embla')
const emblaApi = EmblaCarousel(emblaNode, { loop: false })
// 前後のスライドに移動
emblaApi.scrollPrev()
emblaApi.scrollNext()
Reactでの実装
Reactで使う場合は専用のフックが用意されています。
import React from 'react'
import useEmblaCarousel from 'embla-carousel-react'
export function EmblaCarousel() {
const [emblaRef] = useEmblaCarousel()
return (
<div className="embla" ref={emblaRef}>
<div className="embla__container">
<div className="embla__slide">スライド 1</div>
<div className="embla__slide">スライド 2</div>
<div className="embla__slide">スライド 3</div>
</div>
</div>
)
}
シンプルですよね。refを渡すだけで基本的な動作は完成します。
オプションの設定
const [emblaRef] = useEmblaCarousel({
loop: true, // ループ再生
align: 'start', // スライドの配置(start, center, end)
slidesToScroll: 1, // 一度にスクロールするスライド数
dragFree: false, // 自由ドラッグモード
})
実践的なユースケース
Autoplayプラグインの追加
自動再生が必要な場合は、Autoplayプラグインを追加します。
npm install embla-carousel-autoplay
import useEmblaCarousel from 'embla-carousel-react'
import Autoplay from 'embla-carousel-autoplay'
export function EmblaCarousel() {
const [emblaRef] = useEmblaCarousel({ loop: true }, [Autoplay()])
return (
<div className="embla" ref={emblaRef}>
<div className="embla__container">
<div className="embla__slide">スライド 1</div>
<div className="embla__slide">スライド 2</div>
<div className="embla__slide">スライド 3</div>
</div>
</div>
)
}
Vanilla JavaScriptの場合も同様に、EmblaCarouselの第2引数にオプション、第3引数に
プラグインの配列を渡します。Autoplay()が返すインスタンスはplay() / stop() / isPlaying()
というメソッドを持っており、これを使えば自動再生のON/OFFをボタンから制御できます。
import EmblaCarousel from 'embla-carousel'
import Autoplay from 'embla-carousel-autoplay'
const autoplay = Autoplay({ delay: 1500 })
const emblaApi = EmblaCarousel(emblaNode, { loop: true }, [autoplay])
toggleBtn.addEventListener('click', () => {
autoplay.isPlaying() ? autoplay.stop() : autoplay.play()
})
実際に動かせるサンプルが下です。「停止 / 再開」ボタンでAutoplayプラグインの動作を切り替えられます。
Autoplay({ delay: 1200 })のdelay(ミリ秒)を大きくするほど、スライドが切り替わる間隔が
ゆっくりになります。スライドをドラッグして操作すると、Autoplayプラグインが自動的に一時停止する
挙動も確認できるはずです。
ナビゲーションボタンの実装
import React, { useCallback } from 'react'
import useEmblaCarousel from 'embla-carousel-react'
export function EmblaCarousel() {
const [emblaRef, emblaApi] = useEmblaCarousel()
const scrollPrev = useCallback(() => {
if (emblaApi) emblaApi.scrollPrev()
}, [emblaApi])
const scrollNext = useCallback(() => {
if (emblaApi) emblaApi.scrollNext()
}, [emblaApi])
return (
<div className="embla">
<div className="embla__viewport" ref={emblaRef}>
<div className="embla__container">
<div className="embla__slide">スライド 1</div>
<div className="embla__slide">スライド 2</div>
<div className="embla__slide">スライド 3</div>
</div>
</div>
<button onClick={scrollPrev}>前へ</button>
<button onClick={scrollNext}>次へ</button>
</div>
)
}
useEmblaCarouselの戻り値の2番目がemblaApiで、これを使ってプログラムからカルーセルを操作できます。
前後ボタンだけでなく、現在位置を示すドットのページネーションもEmbla Carouselのコア機能だけで
作れます。emblaApi.scrollSnapList()がスナップポイント数の配列を返すのでその数だけドットを生成し、
クリック時はemblaApi.scrollTo(index)で該当スライドへ移動、on('select', ...)イベントで
現在のドットをハイライトします。
const dots = emblaApi.scrollSnapList().map((_, i) => {
const dot = document.createElement('button')
dot.addEventListener('click', () => emblaApi.scrollTo(i))
return dot
})
emblaApi.on('select', () => {
const selected = emblaApi.selectedScrollSnap()
dots.forEach((dot, i) => dot.classList.toggle('active', i === selected))
})
実際に動かせるサンプルが下です。ドットをクリックすると該当のスライドへジャンプし、ドラッグや ボタン操作をしても現在位置に合わせてドットの色が切り替わります。
ドットの数はscrollSnapList()の長さに追従するので、スライドの枚数を増減させてもコードを
書き換える必要がありません。scrollTo(index)に渡す番号を変えれば、任意のスライドへ直接
ジャンプさせることもできます。
複数スライド表示
複数のスライドを同時に表示したい場合は、CSSを調整します。
.embla__slide {
flex: 0 0 33.33%; /* 3つ同時表示 */
min-width: 0;
padding: 0 10px;
}
CSSで同時表示枚数を変えるだけでなく、slidesToScroll(一度にスクロールする枚数)や
dragFree(スナップせず自由な位置で止まるドラッグモード)といったオプションも組み合わせられます。
オプションを実行時に切り替えたい場合は、emblaApi.reInit(options)に新しい設定を渡すことで
再初期化できます。
const emblaApi = EmblaCarousel(emblaNode, {
align: 'start',
slidesToScroll: 1,
dragFree: false,
})
// 実行時にオプションを差し替える
emblaApi.reInit({ align: 'start', dragFree: true })
実際に動かせるサンプルが下です。チェックボックスでdragFreeを有効にすると、スライドの境目で
スナップせず、指を離した位置で自然に止まる挙動に変わります。
slidesToScrollを3にすると、3枚同時表示のままボタン1回でページ送りのように3枚まとめて
移動するようになります。表示枚数とスクロール単位は独立しているので、用途に合わせて自由に
組み合わせられます。
まとめ
Embla Carouselは、軽量でスワイプ精度が高く、複数フレームワークに対応した実用的なカルーセルライブラリです。
個人的に気に入っているポイントをまとめると、
- バンドルサイズが小さくパフォーマンスが良い
- スワイプの動きが自然で気持ちいい
- 必要な機能だけプラグインで追加できる
- APIがシンプルで学習コストが低い
カルーセルライブラリを探している方は、一度試してみる価値があると思います。公式ドキュメントも充実しているので、実装で困ることは少ないはずです。