Blog

Splideでスライダーを作成!基本の使い方やカスタマイズ方法など

Splideはスライダーのライブラリです。
他ライブラリに依存しておらず、軽量で機能が豊富です。

今まではSwiperを使っていましたが、バージョン9以降が辛い…。特にループ設定した時の挙動が怪しい。
バージョン11になるまで頑張って使い続けてきましたが、ちょっとレイアウトが変わったデザインのスライダーを実装するにあたり限界を感じ、splide.jsに乗り換えました。

すでにもう使っている人も多いようなのですが、今回探して初めて知って実装の簡単さに感動しました。最高です。

勉強するにあたり、テストスライダーを作りました。
下の方に実装例として、イベント登録やエクステンションについても記載しています。

📖Splide v4時点の記事です。

特徴

自分が良いなと感じた点を挙げています。

  • 公式サイトがわかりやすい
    • 日本語(作者様が日本の方のよう)
    • 項目もまとまっててよく使う情報にアクセスしやすい
  • ライブラリが軽量
  • TypeScriptで開発されている
  • 他のライブラリに非依存
  • React,Vue,Svelteのインテグレーションあり
  • エクステンション(拡張機能)の仕組みがある
    • 公式には、自動スクロールやインターセクション(画面内に入った時に再生)などがある
    • 取り外し可能なマイ機能を追加できる
  • breakpoints設定がデフォルトでデスクトップファーストなのが個人的に嬉しい(オプションでモバイルファーストにも変更可能)

WebGLのシェーダーを利用したトランジションの例もあります(スポンサー登録をする必要があります)。

インストールとインポート

公式がわかりやすいです。

NPM、ホスティング、CDNに対応しています。
パッケージをインストーるする場合は、npmなどを用いて@splidejs/splideをインストールします。

私はAstroを使用しているので、CSSはスクリプトから直接読み込みました。

import '@splidejs/splide/css';

もしくはコアスタイルだけなら下記でもOK。

import '@splidejs/splide/css/core';

コアスタイルの方を読み込んだ場合は、スライダーを構築するための最低限のスタイルのみが適用されます。

この場合は、arrowなどのスタイルが適用されないので、ボタンなどをオリジナルにしたい場合に、余計なスタイルを読み込まずにすみます。

HTML

Splideは、root、track、listおよびslideの4つの構成要素から成り立っています。
https://ja.splidejs.com/guides/structure/

<section class="splide">
  <div class="splide__track">
		<ul class="splide__list">
			<li class="splide__slide">Slide 01</li>
			<li class="splide__slide">Slide 02</li>
			<li class="splide__slide">Slide 03</li>
		</ul>
  </div>
</section>

アクセシビリティに関してなど、詳しい情報は公式を参照してください。

JavaScript

マウント

下記のようにSplideを適用します。(初期化は、対象となる要素がすでにロードされている必要があります。)

new Splide( '.splide',{オプション} ).mount();

スライダーをページ内に複数設置したい場合は、.splideの要素に別にidをつけるなどしておき、それぞれインスタンスを作成します。

new Splide( '#slider1' ).mount();
new Splide( '#slider2' ).mount();

オプション

スライダーをカスタマイズするためのさまざまなオプションが用意されています。
new Splideの第二引数にオプションを渡します。

例えば、下記のようにしてループスライダーを作成できます。

new Splide( '.splide', {
  type   : 'loop',
  perPage: 3,
} );

new Splideの第二引数にオプションを渡す他、データ属性による変更も可能です。

<div class="splide" data-splide='{"type":"loop","perPage":3}'>

一部、自分が使ったことのあるオプションを記載します。一覧は公式を参照してください。

  • type
    • スライダーのタイプ。“loop”にするとループになる。(slide、loop、fadeがある)
  • gap
    • スライド間の余白
  • start
    • 最初にアクティブになるスライドのインデックスを指定
  • focus
    • 画面内に複数スライドがある場合、どのスライドをアクティブにするかを指定。‘center’にするとアクティブスライドが真ん中にくる。もしくはアクティブスライドの位置(左から何番目の位置かのインデックス)を入れる
  • autoWidth
    • trueにすると、横幅がコンテンツ幅に合わせて可変になる
  • padding
    • スライダーの左右、あるいは上下の余白を指定。
  • updateOnMove
    • trueにすると、is-activeクラスが移動の始まりと共に付け替えされる。
    • デフォルトのfalseでは移動しきったあとにis-activeがつけ変わるので、activeのアニメーションをしたい場合はtrueにする。
  • breakpoints
    • ブレイクポイントごとにオプションを変更することができる。
  • arrows
    • 左右矢印の表示有無。
  • pagination
    • ページネーション(スライダー下に出る小さい丸)の表示有無。
  • speed
    • スライドのスピードをm秒で指定。
  • cloneStatus
    • is-activeクラスをクローンにも追加するかどうかを決定。

CSS・スタイルについて

splideのcssは、コアのみのCSS / テーマ用CSS / 全てのCSSが用意されており、
ボタンなどのCSS調整必要な場合は、コアのみのCSSを使用するとカスタマイズがしやすいです。

公式<CSSのインポート>

とりあえずスライダーを表示させたいなら全部入のCSSがおすすめです。
importの他にCDNやlinkタグでの利用も可能です(公式参照)。

スライダーは、アクティブなスライドに自動でis-activeクラスがつくようになっているので、is-activeクラスを使って見た目を変えることができます。
また、画面に表示されているスライドにはis-visible、ループのために複製されたスライドにはsplide__slide--cloneクラスがつきます。
次のスライドにはis-next、前のスライドにはis-prevがつきます。

これらを利用して、スライダーのスタイルをカスタマイズすることができます。

実装例

今回実装したデモです。

ポイントとしては、下記があげられます。

  • アクティブスライダーが左によってる
  • アクティブスライダーのスタイルおよび幅が変わる
  • 矢印ボタンはアクティブスライダーの右に常に表示されるよう位置を調整

この辺りをカスタマイズしながら実装していきます。

HTML

HTML全文

splide(splide、splide__track、splide__list、splide__slide)のクラスをつけます。
それ以外は特別なことをしていませんが、splideのArrowsではなくオリジナルで矢印を追加するので、その分のHTMLを追加しています。

ArrowはSVGパスを変更するarrowPathオプションを使ってもよいのですが、今回は完全にカスタマイズできる方のやり方にしました。

Splideの実行

import Splide from '@splidejs/splide';
import '@splidejs/splide/css/core';
import { ArrowPositionExtension } from './ArrowPositionExtension';

class MyFunc {
  slider() {
    //breakpointをcssから取得
    const widthTab =
      Number(
        getComputedStyle(document.body)
          .getPropertyValue('--widthTab')
          .replace(/[^0-9]/g, '')
      ) - 1;

    const splide = new Splide('.splide', {
      type: 'loop',
      autoWidth: true,
      pagination: false,
      padding: { left: '10%' },
      updateOnMove: true,
      speed: 800,
      gap: 30,
      cloneStatus: false,
      breakpoints: {
        [widthTab]: {
          focus: 'center',
          padding: { left: '10%', right: '10%' },
          gap: '15%',
          arrowPositionExtension: {
            offsetLeft: -20,
          },
        },
      },
    });

    splide.mount({
      ArrowPositionExtension,
    });

  }
}

const myFunc = new MyFunc();
window.addEventListener('load', function () {
  myFunc.slider();
});

指定したオプションの説明

スマホの時とはオプションを分けたいので、CSS側からブレークポイントの値を取得してきています。(単に数字でもOK)

以下、指定したオプションの説明です。

  • type:'loop'でループスライドにしています。
  • アクティブスライドは幅が変わるので、autoWidthtrueにしています。
  • pagenationはデフォルトでtrueなので、今回はオフに。
  • padding: { left: '10%' }で、アクティブスライドの左に少し前のスライドが見えるように
  • アクティブスライドにはscaleのアニメーションがあるので、updateOnMovetrueにして、is-activeクラスの付け替えをスライドアニメーション前にしています。(デフォルトではfalseなので、スライドし終わってからis-activeクラスがつきます)
  • cloneStatusfalseにし、ループ用にクローンされたスライドにはis-activeクラスがつかないようにします。
  • arrowPositionExtensionは公式のものではなく、後述のエクステンションで自分で定義したオプションです。

イベントハンドラの登録

今回は矢印の位置をアクティブスライドの右側に調整する必要がありますので、その処理を書いていきます。
イベントハンドラを登録するには、onメソッドを使います。

var splide = new Splide( '.splide' );

splide.on( 'move', function () {
  // 何かの処理
} );

splide.mount();

エクステンション(拡張機能)として作成する方法

メインの関数にイベンハンドラを追加しても良いのですが、今回はいろいろあってエクステンションを使って実装しました。

エクステンションは、mount時に下記のように登録することができます。

import { MySplideExtension } from './MySplideExtension';

    // ...

    splide.mount({
      MySplideExtension
    });

今回はArrowPositionExtensionというファイルを作成しました。
ArrowPositionExtension.tsは以下です。

import type { Splide, Components, Options, BaseComponent } from '@splidejs/splide';

interface ArrowPositionExtensionOptions {
  offsetLeft?: number;
}

declare module '@splidejs/splide' {
  interface Options {
    arrowPositionExtension?: ArrowPositionExtensionOptions;
  }
}

export function ArrowPositionExtension(Splide: Splide, Components: Components, options: Options): BaseComponent {
  function mount() {
    Splide.on('resized', () => {
      adjustArrow();
    });

    Splide.on('mounted', () => {
      adjustArrow();
    });
  }

  function adjustArrow() {
    const arrowEl = Components.Elements.next;
    const activeElIndex = Components.Controller.getIndex();
    const activeElWidth = Components.Layout.slideSize(activeElIndex);
    const positionL = Components.Slides.getAt(activeElIndex).slide.getBoundingClientRect().left;
    const offset = options.arrowPositionExtension?.offsetLeft || 0;
    const val = positionL + activeElWidth + offset;

    arrowEl.style.left = `${val}px`;
  }

  return {
    mount,
  };
}

Extensionの関数は、Splideインスタンス、Splideのコンポーネント、およびオプションを引数として受け取ります。

export function ArrowPositionExtension(Splide: Splide, Components: Components, options: Options): BaseComponent {
  function mount() {

関数内で、コンポーネントがマウントされた際に呼び出されるmount関数と、スライダーが破棄された際に呼び出されるdestroy関数を定義することができます。

今回はmount関数を用いて、Splideのresizedイベントとmountedイベントが発生したときに、矢印要素の位置を調整するイベントハンドラを追加しています。以下の部分↓です。

  function mount() {
    Splide.on('resized', () => {
      adjustArrow();
    });

    Splide.on('mounted', () => {
      adjustArrow();
    });
  }

登録したイベントハンドラは、destory時に全て削除されるようです。(destroy関数にoffの処理を書かなくて良い)

なお、Splide#destroy()あるいはdestroyオプションによりインスタンスが破棄された瞬間、すべてのイベントハンドラが削除されます。mount()メソッドは再度インスタンスがマウントされる際に再び呼ばれますので、イベントハンドラの登録はこの関数内で行うと安全です。

https://ja.splidejs.com/guides/extension/#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%AE%E5%88%A9%E7%94%A8

エクステンションは取り外ししやすいことを前提に作る必要があるので、「疎結合」の観点から他のエクステンションのプロパティを参照せず作成することがすすめられています。

エクステンションは本来はもっと拡張機能らしい拡張機能(?)を定義するための仕様だと思うのですが、何かやってみたい気もあって、ただArrowのPositionを変えるだけのエクステンションを作りました。……が、本気でちゃんとしたものを作る場合、型定義やConstantsなどAutoScrollなど公式にあるエクステンションのコードが参考になります。

Splideのコンポーネントを使って関数を作る

adjustArrowは下記のようになっています。
Splideは、ある特定の機能に特化した、いくつかの小さなコンポーネントから成り立っており、親のArrowPositionExtension関数の引数に渡ってきたComponentsを使うと、いろんなメソッドやオブジェクトにアクセスできます。

function adjustArrow(){
  // 次へ矢印のHTMLエレメントを取得
  const arrowEl = Components.Elements.next;
  // アクティブスライドのインデックスを取得
  const activeElIndex = Components.Controller.getIndex();
  // アクティブスライドの幅を取得
  const activeElWidth = Components.Layout.slideSize(activeElIndex);
  // アクティブスライドの画面左端からの距離を取得
  const positionL = Components.Slides.getAt(activeElIndex).slide.getBoundingClientRect().left;
  // optionsからオフセットの値を取得する
  const offset = options.arrowPositionExtension?.offsetLeft || 0;
  // アクティブスライドの右端のポジション
  const val = positionL + activeElWidth + offset;
  
  // leftのスタイルを付与する
  arrowEl.style.left = `${val}px`;
}

例えば、次へ進む矢印へのHTML要素は、Components.Elements.nextで取得できます。
https://ja.splidejs.com/components/elements/#next

何か欲しいエレメントやメソッドなどがあれば、公式の「コンポーネント」のセクションを参考にすると便利なプロパティや関数が見つかります。

オプションは自分で作ることもできます。今回はarrowPositionExtension.offsetLeftというオプションを作り、オフセットのピクセルが反映されるようにしました。

getBoundingClientRect()は(Splideは関係なく)要素の寸法と、そのビューポートに対する相対位置に関する情報を返します。これがメイン関数にある時は欲しいデータが返ってこなかったのですが(原因よくわからず)、エクステンションに持ってくると取得できました。

まとめ

スライダーライブラリに関してはSwiper9以降使いこなせずにいたので、Splideに出会えて嬉しいです。しかも公式ガイドがわかりやすすぎて、翻訳なしで読めることのありがたみを感じました。

これからお世話になろうと思います。

おすすめの記事 recommend blog

新着 new blog

github