MENU CLOSE

スライダーといえばSwiper!

JavaScript

いまだによく出会うスライダー実装

僕がWEB業界に入ってから6年経ちますが、当時からいまだにメインビジュアルに使いがちなスライダー。制作者側はUIどうなの?とか賛否ありますが、クライアントからの要望で付けることはまだまだ全然あります。

そんな出くわすことの多いスライド実装ですが、そこに時間かけてられないのでちゃちゃっと実装しちゃいたいですよね。

そんな時にオススメなのが「Swiper」というプラグイン。

Swiper

https://idangero.us/swiper/

スライドのプラグインをGoogleで探すといろんなプラグインが出てきますが、Swiperが紹介されている記事がけっこうあるので、知ってる人や実際使っている人もかなり多いんじゃないでしょうか?

僕はもうかれこれ5年くらいはこのプラグインを使っているんじゃないかな?というぐらいスライド実装があればこちらをまず選択します。

読み込んですぐに使えるだけでなく、APIが豊富でカスタマイズ性がとても高くて重宝しています。

では実際に使い方を見ていきましょう!

準備

まずはyarnでインストール

yarn add -D swiper

yarnの公式サイトはこちら。

Yarn

https://yarnpkg.com/ja/

もっと簡単にCDNで試す方はこちら。

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.x.x/css/swiper.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.x.x/css/swiper.min.css">

<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.x.x/js/swiper.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.x.x/js/swiper.min.js"></script>

読み込むのはCSSとJSです。圧縮版と通常版がありますので好きな方を読み込みます。

4.x.xはバージョンです。お好みのバージョンを指定してください。この記事を執筆時の最新バージョンは4.5.0でしたので今回はそれを使います。

yarnでローカルにインストールした場合でもCSSは必要なので環境に合わせて適宜読み込んでおきます。

これでSwiperを使う準備ができました。

基本実装

実際にhtmlとJSを書いていきます。
ここではとりあえずごく基本的なスライダーを作ってみます。

HTML

<div class="swiper-container">
    <div class="swiper-wrapper">
        <div class="swiper-slide">Slide 1</div>
        <div class="swiper-slide">Slide 2</div>
        <div class="swiper-slide">Slide 3</div>
    </div>
    <!-- ページネーション -->
    <div class="swiper-pagination"></div>

    <!-- 前へ/次へ -->
    <div class="swiper-button-prev"></div>
    <div class="swiper-button-next"></div>

</div>

htmlのポイントは、swiper-xxxxとなっているclassが付いている要素です。
swiper-containerswiper-wrapperswiper-slideは必須で、この構造にしないとうまく動かないので注意です。
ページネーションやナビゲーション(前へ/次へボタン)に関してはデフォルト以外のclassを指定することも可能です。ただ個人的にはそのままを使ってあとからCSSを上書きする方が楽です。

JS

<script>
  var mySwiper = new Swiper ('.swiper-container', {
    loop: true,
    pagination: {
      el: '.swiper-pagination',
    },
    navigation: {
      nextEl: '.swiper-button-next',
      prevEl: '.swiper-button-prev',
    }
  })
</script>

JSはこれだけ。本当に説明が要らないくらいシンプル。
一応ここで使うプロパティだけ説明しておくと

  • loop:スライドを無限ループさせるか。true / false
  • pagenation.el:ページネーションを表示させる要素を指定。
  • navigation.nextEl:次へボタンの要素を指定
  • navigation.prevEl:前へボタンの要素を指定

これで基本的なスライダーはできました。
DEMO - Swiper基本

これ以外にも基本的な実装は公式のデモが1番わかりやすいです!

Swiper DEMO

https://idangero.us/swiper/demos/

これだけでもうすぐにでも使えますね!
オプションがかなり豊富なので、公式サイトを見ながら自分なりにカスタマイズできるのがさらにオススメしたいポイントです!

Swiper API

https://idangero.us/swiper/api/

応用編

ここまでで充分通常の案件に使えると思いますが、ちょっと応用してみます。
クライアントの要望でよく遭遇するのが「サムネイル付きのスライダーにしたい」というものです。これは公式のデモにあるのですが、さらによくあるカスタマイズが「スマホではサムネイルをスライドに、PCではサムネイルを全て表示したい」というような画面サイズやデバイズに合わせた挙動の変更を依頼されることがあります。

実際にこれをデモで実装してみます。
完成したものはこちら。

DEMO - 応用編

応用実装

詳細を見ていきます。
デモ用なので画像は入れずにあくまで動きのみの実装になります。

HTML

<div class="cover">
  <div class="frame">
    <div class="swiper-container slide" id="slide">
      <div class="swiper-wrapper">
        <div class="swiper-slide">
          <p>1</p>
        </div>
        <div class="swiper-slide">
          <p>2</p>
        </div>
        <div class="swiper-slide">
          <p>3</p>
        </div>
        ・
        ・
        ・
        <div class="swiper-slide">
          <p>20</p>
        </div>
        <!-- swiper-slideを20個用意する -->
      </div>
      <!-- /.swiper-wrapper -->
      <!-- 前へ/次へ -->
      <div class="swiper-button-prev"></div>
      <div class="swiper-button-next"></div>
    </div>
    <!-- /.swiper-container -->
    <div class="swiper-container thumbnail" id="thumbnail">
      <div class="swiper-wrapper">
        <div class="swiper-slide">
          <p>1</p>
        </div>
        <div class="swiper-slide">
          <p>2</p>
        </div>
        <div class="swiper-slide">
          <p>3</p>
        </div>
        ・
        ・
        ・
        <div class="swiper-slide">
          <p>20</p>
        </div>
        <!-- 同じくswiper-slideを20個用意する -->
      </div>
      <!-- /.swiper-wrapper -->
    </div>
    <!-- /.swiper-container -->
  </div>
  <!-- /.frame -->
</div>
<!-- /.cover -->

ポイントはメインになるスライドと、サムネイル用のスライドを全く同じ順番でつくること。サムネイルの方は小さめの画像を置いてあげると多少は負荷軽減になると思います。

CSS

.cover{
  padding: 30px;
}

.frame{
  max-width: 1080px;
  margin: auto;
}

.slide{
  margin-bottom: 10px;
  border: 1px solid #ccc;
}

.slide .swiper-slide {
  width: 100%;
  height: 300px;
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
  -webkit-align-items: center;
  -ms-flex-align: center;
  align-items: center;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
  -ms-flex-pack: center;
  justify-content: center;
  font-size: 60px;
  font-weight: 900;
}

.thumbnail .swiper-slide{
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
  -webkit-align-items: center;
  -ms-flex-align: center;
  align-items: center;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
  -ms-flex-pack: center;
  justify-content: center;
  padding: 15px;
  font-size: 18px;
  font-weight: 900;
  border: 1px solid #ccc;
}

.thumbnail .swiper-slide::before{
  pointer-events: none;
  opacity: 0;
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  z-index: 10;
  display: block;
  width: 100%;
  height: 100%;
  border: 6px solid #007aff;
  transition: .3s ease;
}

.thumbnail .swiper-slide-thumb-active::before{
  opacity: 1;
}

@media screen and (min-width: 768px) {
  .thumbnail .swiper-wrapper{
    -webkit-flex-wrap:wrap;
    -ms-flex-wrap:wrap;
    flex-wrap:wrap;
  }
  .thumbnail .swiper-slide{
    width: 9.1%;
    height: 60px;
    padding: 30px 0;
    margin-right:1%;
    margin-bottom: 1%;
    font-size: 24px;
  }
  .thumbnail .swiper-slide:nth-child(10n){
    margin-right: 0;
  }
}

CSSはメインのスライドの下にサムネイルがぴったりはまるように調整。
今回は画像も載せていないのであくまで体裁を整えるだけにしました。

JS

続いてここが今回の応用のポイントになるJavaScript。
よく批判の的になる大好きなjQueryを一部使って書いていきます。

<script>
  //メインスライド
  var mainSlideOption = {
    loop           : true,
    navigation     : {
      nextEl : '.swiper-button-next',
      prevEl : '.swiper-button-prev',
    }
  }
  var mainSlide = new Swiper('#slide', mainSlideOption);

  //サムネイルスライド
  var thumbnailOption = {
    loop                  : true,
    spaceBetween          : 10,
    slidesPerView         : 6,
    slideToClickedSlide   : true,
    centeredSlides        : true
  };
  var thumbnail = new Swiper('#thumbnail', thumbnailOption);

  //サムネイルをクリックした時のイベント
  $(document).on('click', '#thumbnail .swiper-slide', (e) => {
    if(thumbnail){
      mainSlide.slideToLoop(thumbnail.realIndex);
    }
    else{
      var index = $('#thumbnail .swiper-slide').index(e.currentTarget);
      mainSlide.slideToLoop(index);
    }
  });

  //メインスライドが動いた時のイベント
  mainSlide.on('slideChange', () => {
    if($(window).innerWidth() < 768){
      thumbnail.slideToLoop(mainSlide.realIndex);
    }
    else {
      $('#thumbnail .swiper-slide').removeClass('is-active');
      $('#thumbnail .swiper-slide').eq(mainSlide.realIndex).addClass('is-active');
    }
  });

  var resizeTimer = null;
  var resizeFlag  = true;
  //リサイズイベント
  $(window).on('load resize', () => {
    if(resizeFlag){
      resizeFlag = false;
      if(resizeTimer){
        window.cancelAnimationFrame(resizeTimer);
      }
      resizeTimer = window.requestAnimationFrame(() => {
        if($(window).innerWidth() >= 768){
          if(thumbnail){
            thumbnail.destroy();
            thumbnail = null;
            $('#thumbnail .swiper-wrapper').removeAttr('style');
            $('#thumbnail .swiper-slide').removeAttr('style');
            $('#thumbnail .swiper-slide').eq(mainSlide.realIndex).addClass('is-active');
          }
        }
        else {
          $('#thumbnail .swiper-slide').removeClass('is-active');
          if(!thumbnail){
            thumbnail = new Swiper('#thumbnail', thumbnailOption);
          }
        }
        resizeFlag = true;
      });
    }
  });

</script>

ちょっと長くなりましたので、ポイントを抑えながら見ていきます。

2つのスライドにSwiperを適用する

//メインスライド
var mainSlideOption = {
  loop           : true,
  navigation     : {
    nextEl : '.swiper-button-next',
    prevEl : '.swiper-button-prev',
  }
}
var mainSlide = new Swiper('#slide', mainSlideOption);

//サムネイルスライド
var thumbnailOption = {
  loop                  : true,
  spaceBetween          : 10,
  slidesPerView         : 6,
  slideToClickedSlide   : true,
  centeredSlides        : true
};
var thumbnail = new Swiper('#thumbnail', thumbnailOption);

まずはじめにSwiperを各スライド要素に適用します。
メインスライドはループとナビゲーションボタンを付けただけのシンプルなものに。サムネイルスライドは同じくループあり・6枚表示にしてセンター表示に設定しておきます。

サムネイルをクリックした時にメインスライドを連動させる

2つのスライドができましたが、今はまだ連動性はなく別々に動くスライドです。連動させましょう。

//サムネイルをクリックした時のイベント
$(document).on('click', '#thumbnail .swiper-slide', (e) => {
  if(thumbnail){
    mainSlide.slideToLoop(thumbnail.realIndex);
  }
  else{
    var index = $('#thumbnail .swiper-slide').index(e.currentTarget);
    mainSlide.slideToLoop(index);
  }
});

まず、SwiperのAPIに.slideToLoopという引数に指定したスライドにスライドさせるメソッドがあるのでこれを使います。似たようなメソッドで.slideToがありますが、こちらは今回のようにループを設定しているスライドでは扱いにくいので.slideToloopを使いましょう。

.slideToloopの引数に渡すのは同じくSwiperのAPIにあるプロパティのrealIndexを使います。realIndexには現在activeになっているスライドの番号が入っています。サムネイルスライドのrealIndexを使ってメインスライドを.slideToLoopで動かします。

mainSlide.slideToLoop(thumbnail.realIndex);

これでサムネイルをクリックした時に両方のスライドがactiveになって連動するようになります。

if文で変数thumbnailがある時とそうでない時になっていますが、今回はレスポンシブでPCの時はSwiperを削除するので、削除した時は当然realIndexというSwiper独自のプロパティも削除されます。その場合はjQueryの.indexメソッドを使って要素の順番を渡してあげます。

var index = $('#thumbnail .swiper-slide').index(e.currentTarget);
mainSlide.slideToLoop(index);

これでまず1つめの連動ができました。

メインスライドが動いた時にサムネイルを連動させる

次は逆にメインスライドをナビゲーションやスワイプで動かした時にサムネイルのactiveをさせる処理を書いていきます。

//メインスライドが動いた時のイベント
mainSlide.on('slideChange', () => {
  if($(window).innerWidth() < 768){
    thumbnail.slideToLoop(mainSlide.realIndex);
  }
  else {
    $('#thumbnail .swiper-slide').removeClass('is-active');
    $('#thumbnail .swiper-slide').eq(mainSlide.realIndex).addClass('is-active');
  }
});

ここではSwiperのAPIでslideChangeイベントを使っていきます。
このイベントは現在アクティブなスライドが変更されたときに発生します。つまりスライドが変わった時ですね。このタイミングでさっきと逆にメインスライドのrealIndexプロパティを使ってサムネイルスライドのslideToLoopに適用してやればOKです。

thumbnail.slideToLoop(mainSlide.realIndex);

そしてこちらも同じくレスポンシブでサムネイルスライドが削除されるので、削除された後のスライド要素はrealIndexプロパティが使えないのでjQueryでclassの付け替えをします。

$('#thumbnail .swiper-slide').removeClass('is-active');
$('#thumbnail .swiper-slide').eq(mainSlide.realIndex).addClass('is-active');

追加したis-activeクラスにcssを当ててやればOKです。

これでメインスライド側でactiveになったスライドがサムネイルに連動するようになりました。

レスポンシブでサムネイルのスライドあり・なしを切り替え

ここが本題のところです。

var resizeTimer = null;
var resizeFlag  = true;
//リサイズイベント
$(window).on('load resize', () => {
  if(resizeFlag){
    resizeFlag = false;
    if(resizeTimer){
      window.cancelAnimationFrame(resizeTimer);
    }
    resizeTimer = window.requestAnimationFrame(() => {
      if($(window).innerWidth() >= 768){
        if(thumbnail){
          thumbnail.destroy();
          thumbnail = null;
          $('#thumbnail .swiper-wrapper').removeAttr('style');
          $('#thumbnail .swiper-slide').removeAttr('style');
          $('#thumbnail .swiper-slide').eq(mainSlide.realIndex).addClass('is-active');
        }
      }
      else {
        $('#thumbnail .swiper-slide').removeClass('is-active');
        if(!thumbnail){
          thumbnail = new Swiper('#thumbnail', thumbnailOption);
        }
      }
      resizeFlag = true;
    });
  }
});

細かく見ていきましょう。

まずはjQueryでリサイズイベントを追加します。

var resizeTimer = null;
var resizeFlag  = true;
//リサイズイベント
$(window).on('load resize', () => {
  if(resizeFlag){
    resizeFlag = false;
    if(resizeTimer){
      window.cancelAnimationFrame(resizeTimer);
    }
    resizeTimer = window.requestAnimationFrame(() => {

   //ここにリサイズした時の処理を書く

    resizeFlag = true;
    });
  }
});

リサイズイベントはそのまま使うと思っている以上に連続で発生しまくってバグが出やすいのでrequestAnimationFrameを使って最適化しておきます。(requestAnimationFrameに対応していないブラウザの場合はsetTimeoutで代用できますが、ここでは省略します)

あとはリサイズのタイミングでサムネイルスライドにSwiperを適用したり、削除したりする処理を書いていきます。

//ウィンドウサイズ768px以上の場合
if($(window).innerWidth() >= 768){
  //サムネイルスライドが有れば削除
  if(thumbnail){
    thumbnail.destroy();
    thumbnail = null;
    $('#thumbnail .swiper-wrapper').removeAttr('style');
    $('#thumbnail .swiper-slide').removeAttr('style');
    //activeなサムネイルにクラスを付与
    $('#thumbnail .swiper-slide').eq(mainSlide.realIndex).addClass('is-active');
  }
}
else {
  //ウィンドウサイズ768px未満の場合
  //Swiperを再適用する場合はこちらで付けたis-activeクラスは削除しておく
  $('#thumbnail .swiper-slide').removeClass('is-active');
  if(!thumbnail){
    thumbnail = new Swiper('#thumbnail', thumbnailOption);
  }
}

ここでのポイントは、SwiperのAPIにある.destroyというメソッド。
.destroyを実行するとSwiperインスタンスは削除されますが、各要素についたstyle要素は削除されずに残ってしまうのでjQueryの.removeAttrを使ってSwiperによって追加されたstyle属性を削除しておきます。

さらに「メインスライドが動いた時にサムネイルを連動させる」部分で書いたクラスを付与する処理は、今回は768px以上の場合だけ適用させるのでそれぞれにis-activeクラスの追加・削除処理を書いておきます。

完成

DEMO - 応用編

これで少し複雑な要望にも対応できますね!

まとめ

今回はスライダーのプラグインSwiperとその使い方についてメモしました。
応用編はちょっと面倒臭い処理にはなりますが、たまに要望としてあるので頭の片隅にでもおいておくと出くわしたときにすぐ対応できるので良いかと思います。

本当にAPIが豊富で他にもいろいろと応用できることがあると思うので、また今後Swiperを使ったちょっと複雑な案件があれば第2弾で紹介したいと思います!

記事一覧

Related

JS
inoue
inoue
TIPS

Intersection Observerを使って画面内に要素が入ったらアニメーションさせる

wordpress
inoue
inoue
TIPS

普通のレンタルサーバーでできるWebページ高速化

wordpress
inoue
inoue
TIPS

【WordPress】便利なアクションフック「template_redirect」

wordpress
inoue
inoue
TIPS

【WordPress】REST APIで独自エンドポイントの作り方

wordpress
inoue
inoue
TIPS

【WordPress】画像に自動付与されるsrcset属性を削除する

wordpress
inoue
inoue
TIPS

WordPressでよく使うプラグイン15選!

ブログ記事一覧
  • HOME
  • TIPS
  • スライダーといえばSwiper!