Written by Toshiki

メイン画像とサムネイルを連動させて画像を切り替える

JavaScript Web制作

こんにちは、トシキです。
今回は、メイン画像とサムネイルを連動させて、画像を切り替える方法について解説します。

本記事の内容

スポンサードサーチ

【1】メイン画像とサムネイルを連動させて画像を切り替える

メイン画像が上に1枚で、その下にサムネイルが4枚並んでいるレイアウトになります。

See the Pen メイン画像とサムネイルを連動させて画像を切り替える by tosshii (@totototosshii) on CodePen.

1-1. HTML



<div class="bl_imgSwitcher" id="js_imgSwitcher">
  <div class="bl_imgSwitcher_main">
    <img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju7U8esONERDN_s7GbaKtQbHoaZ9ogxlzbcSf9I8_JbyCrXUM9BvvFFg-1LwbMZHM2x-5pBYWxlhTSqPa_9eLwZeWY2ZzHhVg_iQqb0PRsSxP-WxElIjlm1BT1jy0fCRtHAckDbyCjdd-u/s1600/no_image_logo.png" alt="No Image">
  </div>
  <div class="bl_imgSwitcher_thumb">
    <button class="bl_imgSwitcher_btn" type="button"><img src="https://picsum.photos/id/229/1000/800" alt="ダミー01"></button>
    <button class="bl_imgSwitcher_btn" type="button"><img src="https://picsum.photos/id/230/800/1000" alt="ダミー02"></button>
    <button class="bl_imgSwitcher_btn" type="button"><img src="https://picsum.photos/id/231/1200/800" alt="ダミー03"></button>
    <button class="bl_imgSwitcher_btn" type="button"><img src="https://picsum.photos/id/232/800/1200" alt="ダミー04"></button>
  </div>
</div>

メイン画像<div class="bl_imgSwitcher_main">の直下には、ダミーのimgを用意します(画像はいらすとやから借りました)。
srcが空だとHTML構文エラーになるので、ダミー用のsrcは用意してください。

各サムネイルのimgは、<button class="bl_imgSwitcher_btn" type="button">で囲んでいます(画像はLorem Picsumから借りました)。

1-2. CSS



/* SCSS */
body{
  margin-top: 20px;
}

// ラッパー
.bl_imgSwitcher {
  max-width: 900px;
  margin-inline: auto;
}

// メイン画像のエリア
.bl_imgSwitcher_main {
  aspect-ratio: 3/2;
  border-radius: 20px;
  overflow: hidden;

  img {
    width: 100%;
    object-fit: cover;
  }
}

// サムネイル画像のエリア
.bl_imgSwitcher_thumb {
  display: flex;
  gap: 0 4%;
  margin-top: 4%;
}

// サムネイル画像の各ボタン
.bl_imgSwitcher_btn {
  width: 22%;
  overflow: hidden;
  border-radius: 20px;
  position: relative;

  &::before {
    content: "";
    border-radius: inherit;
    position: absolute;
    inset: 0;
    z-index: 10;
    transition: background-color .4s;
  }

  @media (any-hover: hover) {
    &:hover::before {
      background-color: rgb(255 255 255/.5);
    }
  }

  &:focus-visible::before {
    background-color: rgb(255 255 255/.5);
  }

  img {
    width: 100%;
    aspect-ratio: 1;
    object-fit: cover;
  }
}

// .is_activeクラスが付与されたら、サムネイル画像に半透明の白背景を適用
.bl_imgSwitcher_btn.is_active::before {
  background-color: rgb(255 255 255/.5);
}

現在選択されているサムネイル<button class="bl_imgSwitcher_btn" type="button">.is_activeクラスを付与して、擬似要素beforeに半透明の白背景を適用します。
また、ホバーとフォーカス時にも同様のスタイルを指定しています。

1-3. JavaScript



window.addEventListener('DOMContentLoaded', () => {
  const imgSwitcher = document.getElementById('js_imgSwitcher');
  if (imgSwitcher) {
    const mainImg = document.querySelector('.bl_imgSwitcher_main img');
    const thumbBtns = document.querySelectorAll('.bl_imgSwitcher_btn');
    // 1番目のサムネイル画像をメイン画像に適用し、.is_activeクラスを付与
    mainImg.src = thumbBtns[0].querySelector('img').src;
    mainImg.alt = thumbBtns[0].querySelector('img').alt;
    thumbBtns[0].classList.add('is_active');
    // サムネイル画像がフォーカスされたときの処理
    thumbBtns.forEach(thumbBtn => {
      thumbBtn.addEventListener('focus', switchImage);
    });
    function switchImage() {
      const img = this.querySelector('img');
      mainImg.style.transition = 'opacity .3s ease-out';
      mainImg.style.opacity = 0;
      setTimeout(() => {
        mainImg.src = img.src;
        mainImg.alt = img.alt;
        mainImg.style.opacity = 1;
      }, 300);
      thumbBtns.forEach(thumbBtn => thumbBtn.classList.remove('is_active'));
      this.classList.add('is_active');
    }
  }
});
  

const imgSwitcher = document.getElementById('js_imgSwitcher');
if (imgSwitcher)

id="js_imgSwitcher"を取得して、その要素が存在しないページではコンソールエラーが出ないように条件分岐しています。



const mainImg = document.querySelector('.bl_imgSwitcher_main img');
const thumbBtns = document.querySelectorAll('.bl_imgSwitcher_btn');
// 1番目のサムネイル画像をメイン画像に適用し、.is_activeクラスを付与
mainImg.src = thumbBtns[0].querySelector('img').src;
mainImg.alt = thumbBtns[0].querySelector('img').alt;
thumbBtns[0].classList.add('is_active');

メイン画像のimgと、全てのサムネイルのbutton要素を取得して変数へ代入します。
その後、取得した1番目thumbBtns[0]のサムネイル情報(srcalt)を、メイン画像のimgに代入しています。
最後に1番目のサムネイルに.is_activeクラスを付与して、半透明の白背景を適用しています。
ここまでがページにアクセスした時の初期状態になります。



// サムネイル画像がフォーカスされたときの処理
thumbBtns.forEach(thumbBtn => {
  thumbBtn.addEventListener('focus', switchImage);
});

任意のサムネイルthumbBtnがフォーカス(クリックやTabキー移動)されたら、後に解説するswitchImage関数を実行します。



function switchImage() {
  const img = this.querySelector('img');
  mainImg.style.transition = 'opacity .3s ease-out';
  mainImg.style.opacity = 0;
  setTimeout(() => {
    mainImg.src = img.src;
    mainImg.alt = img.alt;
    mainImg.style.opacity = 1;
  }, 300);
  thumbBtns.forEach(thumbBtn => thumbBtn.classList.remove('is_active'));
  this.classList.add('is_active');
}

始めに先ほどのthumbBtn.addEventListener('focus', switchImage);でフォーカスされた、サムネイルのimg要素を取得して定数imgに代入します。
次にメイン画像mainImgtransitionopacityのスタイルを指定して、opacityは透明にします。

setTimeoutで0.3秒後に以下の処理を実行しています。

  • 定数imgに代入したサムネイル情報(srcalt)をメイン画像のimgに代入
  • opacityで透明にしたメイン画像を表示

前もってmainImg.style.transition = 'opacity .3s ease-out';を指定しているため、opacityはフワッと表示されます。



thumbBtns.forEach(thumbBtn => thumbBtn.classList.remove('is_active'));
this.classList.add('is_active');

.is_activeクラスを全てのサムネイルからを外したのち、フォーカスされたサムネイルにのみ付与してます。

【2】まとめ

今回はサムネイルの情報をメイン画像に適用して表示させるシンプルな動作でしたが、もし前後矢印やドット(いわゆるスライダー要素)が必要になると複雑化するので、その場合はSplideなどのスライダーライブラリを採用するのが良いと思います。
以上になります。

人気記事Webサイトにフォントサイズ変更ボタンを実装する方法(jQuery使用)

人気記事【脱jQuery】スクロールしたら画面上部に追従メニューを表示する方法