【Swiper】画像クリックしたら拡大表示するカルーセルスライダーの作り方【モーダルウィンドウ+スライダー】

本記事では、Swiperで画像をクリックしたら拡大表示するカルーセルスライダーの作り方を解説します。ようはモーダルウィンドウ+スライダーなわけですが、、汗

よくあるデザインパターンかと思うので備忘録も兼ねて解説します。

完成図

コピペしてすぐに使えるように用意してますので必要な方は下記からどうぞ!

<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@9/swiper-bundle.min.css" />
  <link rel="stylesheet" href="./style.css">
</head>

<body style="margin: 0;">

  <!-- メインスライダー -->
  <div class="swiper" id="mainSwiper">
    <div class="swiper-wrapper">
      <div class="swiper-slide" data-slide-index="0">
        <img src="https://placehold.jp/3d4070/ffffff/500x350.png" alt="">
      </div>
      <div class="swiper-slide" data-slide-index="1">
        <img src="https://placehold.jp/304512/ffffff/500x350.png" alt="">
      </div>
      <div class="swiper-slide" data-slide-index="2">
        <img src="https://placehold.jp/d22d2d/ffffff/500x350.png" alt="">
      </div>
    </div>
    <div class="swiper-button-prev"></div>
    <div class="swiper-button-next"></div>
  </div>
  <!-- メインスライダー END -->

  <!-- モーダル部分 -->
  <div class="js-modal modal">
    <div class="modal-bg js-close-btn"></div>
    <div class="modal-content">
      <div class="swiper" id="modalSwiper">
        <div class="swiper-wrapper">
          <div class="swiper-slide">
            <img src="https://placehold.jp/3d4070/ffffff/500x350.png" alt="">
          </div>
          <div class="swiper-slide">
            <img src="https://placehold.jp/304512/ffffff/500x350.png" alt="">
          </div>
          <div class="swiper-slide">
            <img src="https://placehold.jp/d22d2d/ffffff/500x350.png" alt="">
          </div>
        </div>
        <div class="swiper-pagination"></div>
      </div>
    </div>
  </div>
  <!-- モーダル部分 END-->

  <!-- CDN読み込み -->
  <script src="https://cdn.jsdelivr.net/npm/swiper@9/swiper-bundle.min.js"></script>

  <!-- 独自JS -->
  <script src="./index.js">

</body>

</html>

/***************************
*
** レイアウト関係
*
***************************/
#mainSwiper {
  width: 500px;
  max-width: 90%;
  height: 350px;
}

#mainSwiper .swiper-slide {
  cursor: zoom-in;
}

/* 画像のサイズ調整 */
.swiper-slide img {
  height: 100%;
  width: 100%;
  object-fit: cover;
}

/***************************
*
** モーダルのスタイル
*
***************************/

.modal {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  height: 100vh;
  z-index: 9999;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.35s;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}

.modal.active {
  opacity: 1;
  pointer-events: auto;
}

.modal-bg {
  position: absolute;
  background: rgba(0, 0, 0, 0.7);
  height: 100%;
  width: 100%;
  left: 0;
  top: 0;
}

.modal-content {
  max-width: 90%;
  width: 800px;
  margin: 0 auto;
}
    // メインスライダーの初期化・設定
    const swiper = new Swiper('#mainSwiper', {
      navigation: {
        prevEl: '.swiper-button-prev',
        nextEl: '.swiper-button-next',
      },
      loop: true,
    });

    // モーダル部分のスライダー初期化・設定
    const modalSwiper = new Swiper('#modalSwiper', {
      pagination: {
        el: '.swiper-pagination',
        clickable: true,
      },
      loop: true,
    });

    // 定数定義
    const slides = document.querySelectorAll('#mainSwiper .swiper-slide');
    const modalClose = document.querySelector('.js-close-btn');
    const modal = document.querySelector('.js-modal');

    // メインスライダーの画像クリック時の処理
    slides.forEach(function (slide) {
      slide.addEventListener('click', function () {
        let modalIndex = slide.dataset.slideIndex;
        modalSwiper.slideTo(modalIndex);
        modal.classList.add('active');
      });
    });

    // モーダルを閉じる処理
    modalClose.addEventListener('click', function () {
      modal.classList.remove('active');
      slideIndex = "";
    });
  </script>

【コード解説】画像クリックで拡大表示するスライダーの作り方

HTML

まずはHTMLから見ていきましょう。HTMLは下記。※<body>内です。その他は省略

  <!-- メインスライダー -->
  <div class="swiper" id="mainSwiper">
    <div class="swiper-wrapper">
      <div class="swiper-slide" data-slide-index="0">
        <img src="https://placehold.jp/3d4070/ffffff/500x350.png" alt="">
      </div>
      <div class="swiper-slide" data-slide-index="1">
        <img src="https://placehold.jp/304512/ffffff/500x350.png" alt="">
      </div>
      <div class="swiper-slide" data-slide-index="2">
        <img src="https://placehold.jp/d22d2d/ffffff/500x350.png" alt="">
      </div>
    </div>
    <div class="swiper-button-prev"></div>
    <div class="swiper-button-next"></div>
  </div>
  <!-- メインスライダー END -->

  <!-- モーダル部分 -->
  <div class="js-modal modal">
    <div class="modal-bg js-close-btn"></div>
    <div class="modal-content">
      <div class="swiper" id="modalSwiper">
        <div class="swiper-wrapper">
          <div class="swiper-slide">
            <img src="https://placehold.jp/3d4070/ffffff/500x350.png" alt="">
          </div>
          <div class="swiper-slide">
            <img src="https://placehold.jp/304512/ffffff/500x350.png" alt="">
          </div>
          <div class="swiper-slide">
            <img src="https://placehold.jp/d22d2d/ffffff/500x350.png" alt="">
          </div>
        </div>
        <div class="swiper-pagination"></div>
      </div>
    </div>
  </div>
  <!-- モーダル部分 END-->

HTMLのポイント

メインスライダーのスライドにdata-slide-indexを設定しています。このdata属性はJavascriptで使用します。のちに詳しく解説しますが、モーダルのスライドとメインのスライドの表示を合わせるためのものです。

あとは、モーダル部分のHTMLですね。

<div class="js-modal modal"> <!-- モーダル -->
  <div class="modal-bg js-close-btn"></div> <!-- モーダルの背景 -->
  <div class="modal-content"> <!-- モーダルの中身 -->
    <div class="swiper" id="modalSwiper">
      <div class="swiper-wrapper">
        <div class="swiper-slide">
          <img src="https://placehold.jp/3d4070/ffffff/500x350.png" alt="">
        </div>
        <div class="swiper-slide">
          <img src="https://placehold.jp/304512/ffffff/500x350.png" alt="">
        </div>
        <div class="swiper-slide">
          <img src="https://placehold.jp/d22d2d/ffffff/500x350.png" alt="">
        </div>
      </div>
      <div class="swiper-pagination"></div>
    </div>
  </div>
</div>

モーダルについては細かく解説しません。すんません

モーダル内を開いた状態でもスライドができるように、ここでもSwiperを使用しています。これも後で使います!

CSSのポイント

モーダル部分

/*モーダルの元*/
.modal {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  z-index: 9999;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.35s;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}
/*画像クリック時のモーダルの状態*/
.modal.active {
  opacity: 1;
  pointer-events: auto;
}

CSSのポイントはモーダル部分くらいですね。

  • 親要素となるmodalは、positon:fixedで固定。
  • modalは最初非表示にしたいので、opacity: 0を指定。あとクリックイベントを取り消すためにpointer-events:noneを指定。
  • modal.activeは画像クリック時にactiveクラスを付与する用。opacity: 1pointer-events:autoで表示とクリックをオンにする

おまけ:カーソルを虫眼鏡にする

#mainSwiper .swiper-slide {
  cursor: zoom-in;
}

メインスライダーのカーソルを虫眼鏡にしています。cursor: zoom-inを指定することで虫眼鏡のプラスになります。指定はぶっちゃけどっちでもいいですが、クリックしたら大きくなるのがわかるので、あったら優しいかもぬ。

Javascript

さてさて、本題のJavascriptを見ていきましょう。全体のコードは下記です。

// メインスライダーの初期化・設定
const swiper = new Swiper('#mainSwiper', {
  navigation: {
    prevEl: '.swiper-button-prev',
    nextEl: '.swiper-button-next',
  },
  loop: true,
});

// モーダル内のスライダー初期化・設定
const modalSwiper = new Swiper('#modalSwiper', {
  pagination: {
    el: '.swiper-pagination',
    clickable: true,
  },
  loop: true,
});

// 定数定義
const slides = document.querySelectorAll('#mainSwiper .swiper-slide');
const modalClose = document.querySelector('.js-close-btn');
const modal = document.querySelector('.js-modal');

// メインスライダーの画像クリック時の処理
slides.forEach(function (slide) {
  slide.addEventListener('click', function () {
    let modalIndex = slide.dataset.slideIndex;
    modalSwiper.slideTo(modalIndex);
    modal.classList.add('active');
  });
});

// モーダルを閉じる処理
modalClose.addEventListener('click', function () {
  modal.classList.remove('active');
  slideIndex = "";
});

メインスライダーの設定

// メインスライダーの初期化・設定
const swiper = new Swiper('#mainSwiper', {
  navigation: {
    prevEl: '.swiper-button-prev',
    nextEl: '.swiper-button-next',
  },
  loop: true,
});

ポイントはほぼなし。どのオプションも必須ではないです。お好みで

navigationで矢印を表示するようにしています。あと、loopを設定することでループするようにしています

モーダル内のスライダー

// モーダル内のスライダー初期化・設定
const modalSwiper = new Swiper('#modalSwiper', {
pagination: {
el: '.swiper-pagination',
clickable: true,
},
loop: true,
});

今回はモーダルが開いた状態でもモーダル内でスライドできるよにしました。そのためモーダル内のスライダー処理も設定しています。

モーダルの動作設定

// 定数定義
const slides = document.querySelectorAll('#mainSwiper .swiper-slide');
const modalClose = document.querySelector('.js-close-btn');
const modal = document.querySelector('.js-modal');

// メインスライダーの画像クリック時の処理
slides.forEach(function (slide) {
  slide.addEventListener('click', function () {
    let modalIndex = slide.dataset.slideIndex; // クリックしたらスライドのdata属性を取得
    modalSwiper.slideTo(modalIndex); // モーダルのスライドをクリックされた番号のスライドにスライドする
    modal.classList.add('active'); // モーダルにactiveクラスを追加
  });
});

// モーダルを閉じる処理
modalClose.addEventListener('click', function () {
  modal.classList.remove('active'); // モーダルのactiveクラスを削除
});

本記事のポイントです!

メインスライダーのスライドクリック時の処理から説明します。

8行目までの処理はたぶんわかりますね。メインスライダーのすべてのスライドを取得して、スライドをクリックしたときの処理を記述しています。

大事なのは9行目でdata属性を取得しているところです。ここでは何番目のスライドかを取得しています。この番号は次の10行目で使用します。

クリックしたスライドと順番が一致するスライドをモーダルに表示させる

10行目では、modalSwiper.slideTo(modalIndex);と書きました。

これはSwiperのslideToという関数でして、第一引数にはスライド番号が入ります。詳細は以下チェック。

公式の説明

「速度」パラメーターに等しい期間、「インデックス」パラメーターに等しいインデックス番号を持つスライドへのトランジションを実行します。(英訳)

Swiper API

swiper.slideTo(index, speed, runCallbacks)

  • index – number – スライドのインデックス番号。
  • speed – number – 遷移時間 (ミリ秒単位)。
  • runCallbacks – boolean – false に設定すると (デフォルトでは true)、transition は遷移イベントを生成しません。
modal.classList.add('active'); // モーダルにactiveクラスを追加

あとは、モーダルにアクティブクラスを付与して、モーダルを表示させます。

閉じるときの処理は以下。

// モーダルを閉じる処理
modalClose.addEventListener('click', function () {
  modal.classList.remove('active'); // モーダルのactiveクラスを削除
});

modalCloseはモーダルの背景です。(バツボタン作るのめんどかったのでこれにしました。笑)

まとめ

というわけで以上。スライダー+モーダルウィンドウはよくあるかもなので、ぜひ試してみては。

多分やり方はもっとあると思いますが、一つのやり方としてよかった参考にしてくださーい🙇‍♂️

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA