Written by Toshiki

メインとサブを連動させた画像切り替えの実装(jQuery使用)

Web制作 プログラミング

こんにちは、トシキです。
今回は「サブの画像をクリックしたら、メインの画像が連動して切り替わる」実装の仕方を紹介します。

本記事の内容

コードの解説

実際の動きはこんな感じになります。

コードの解説

こちらのポートフォリオからも確認できます↓

HTML

  
    <div class="bl_mediaCat_imgWrapper">
      <figure class="bl_mediaCat_img"><img src="https://picsum.photos/seed/picsum/1000/800"></figure>
      <ul>
        <li class="bl_mediaCat_imgItem"><img src="https://picsum.photos/seed/picsum/1000/800"></li>
        <li class="bl_mediaCat_imgItem"><img src="https://picsum.photos/seed/picsum/800/1000?grayscale"></li>
        <li class="bl_mediaCat_imgItem"><img src="https://picsum.photos/seed/picsum/1200/800?blur"></li>
        <li class="bl_mediaCat_imgItem"><img src="https://picsum.photos/seed/picsum/800/1200?grayscale"></li>
      </ul>
    </div>
  

メイン画像が1枚でサブ画像が4枚の構成

メイン画像は<figure>で囲み、その下にはサブ画像を<ul>で配置しています。
jQueryを使い、サブの<li>直下の<img>をクリックしたら、その画像がメイン部分に表示されるようにします。

CSS

  
    /* メイン画像 */
    .bl_mediaCat_img {
      margin: 0 0 16px 0;
      overflow: hidden;
      padding-top: 65.755%;
      position: relative;
    }
    
    .bl_mediaCat_img img {
      -webkit-transform: translateY(-50%);
      -o-object-fit: cover;
      border-radius: 20px;
      height: 100%;
      left: 0;
      object-fit: cover;
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      width: 100%;
    }
    
    /* サブ画像 */
    .bl_mediaCat_imgWrapper ul {
      display: flex;
      justify-content: space-between;
      padding-left: 0;
      list-style: none;
    }
    
    .bl_mediaCat_imgItem {
      cursor: pointer;
      padding-top: 22.947%;
      position: relative;
      width: 22.947%;
    }
    
    .bl_mediaCat_imgItem img {
      -webkit-transform: translateY(-50%);
      -o-object-fit: cover;
      border: 1px solid transparent;/* ① */
      border-radius: 20px;
      height: 100%;
      left: 0;
      object-fit: cover;
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      width: 100%;
    }
    
    /* [.is_active]クラスが付与されたら、サブ画像にオレンジのボーダーを付ける */
    .bl_mediaCat_imgItem.is_active img {
      border: 1px solid #F7B500;
    }
  

画像のアスペクト比はpadding-topで設定

padding-topで画像エリアの高さを確保し、中の画像を絶対配置にしています。
ただaspect-ratioの方が記述が短く済みますので、対応するブラウザの範囲に応じて使い分けてみてください。
検証したらCSSがスッキリして好感触でした。
とはいえ、記事執筆時点(2021/10)では実案件に使用するのはまだ早いかなぁという印象です。

①について

サブ画像には初期状態でborder: 1px solid transparent;を指定。
初期状態で指定していないとクリックされた時に、[.is_active]で付与されるオレンジのボーダー分サイズが変わり、画像のガタ付きが起きてしまいます。
ですので、初期の時点でボーダーを透明の状態で指定しています。

jQuery

  
    // 画像切り替えクリックイベント
    $(window).on('load', function () {
      // 最初のliにis_activeを追加
      $('.bl_mediaCat_imgItem:first-of-type').addClass('is_active');/* ① */
    });

    $(function () {
      // サブ画像がクリックされた時
      $('.bl_mediaCat_imgItem img').on('click', function () {
        // クリックされたサブ画像のsrcを変数imgに代入
        let img = $(this).attr('src');/* ② */
        // サブの[.bl_mediaCat_imgItem.is_active img]から[.is_active]を削除(ボーダーが消える)
        $('.bl_mediaCat_imgItem').removeClass('is_active');/* ③ */
        // クリックされたサブ画像の親要素[.bl_mediaCat_imgItem]に[.is_active]を追加(ボーダーが付く)
        $(this).parent().addClass('is_active');/* ④ */
        // メイン画像を0.05秒かけてフェードアウト
        $('.bl_mediaCat_img img').fadeOut(50, function () {/* ⑤ */
          // メイン画像のsrcに、クリックされたサブ画像のsrcを読み込んでフェードイン
          $(this).attr('src', img).on('load', function () {/* ⑥ */
            $(this).fadeIn();/* ⑦ */
          });
        });
      });
    });
  

①について

ページが読み込まれた時に、1枚目のサブ画像[.bl_mediaCat_imgItem]に[.is_active]クラスを追加します。
これで<img>にオレンジのボーダーが適用されます。

  
    $('.bl_mediaCat_imgItem:first-of-type').addClass('is_active');
  
  
    /* CSS */
    .bl_mediaCat_imgItem.is_active img {
      border: 1px solid #F7B500;
    }
  

②について

クリックされたサブ画像のsrc属性の値を取得して、変数imgに代入しています。
.attr()はHTMLの属性値(idやclass、hrefなど)を取得・設定ができるメソッドです。

  
    let img = $(this).attr('src');
  

③について

サブ画像[.bl_mediaCat_imgItem]から[.is_active]クラスを削除します。
これで全ての<img>からオレンジのボーダーが適用されている部分が無くなります。

  
    $('.bl_mediaCat_imgItem').removeClass('is_active');
  

④について

クリックされたサブ画像<img>$(this)の親要素[.bl_mediaCat_imgItem]に[.is_active]を追加します。
.parent()を使うことで、今回は指定要素の1階層上の親要素[.bl_mediaCat_imgItem]が取得できます。

  
    $(this).parent().addClass('is_active');
  

⑤について

メイン画像[.bl_mediaCat_img img]を0.05秒かけて非表示にします。
時間と関数を引数に入れる場合は.fadeOut(時間, 関数)のように記述し、時間はミリ秒で設定します。
(今回は0.05秒なので50ミリ秒)

  
    $('.bl_mediaCat_img img').fadeOut(50, function ()
  

⑥について

.attr()の第1引数でメイン画像のsrc属性を取得して、第2引数には②でサブ画像から取得したsrc属性値の変数imgを指定します。
これでメイン画像のsrcにサブ画像のsrcが上書きされます。

  
    $(this).attr('src', img)
  

上書きされたら、.on('load', function ()が処理されて後述の⑦が実行されます。

⑦について

メイン画像が表示されます。
.fadeIn()の引数に秒数指定がない場合は、400ミリ秒(0.4秒)かけて表示されます。

  
    $(this).fadeIn();
  

終わりに

終わりに

jQueryが多少複雑に見えますが、分解していくと比較的よく使うメソッドばかりでした。(.attr()は曖昧だったので勉強になりました)
この記事作成のきっかけは、ポートフォリオ作成中にSlickを使ったスライダーを実装しようとしましたが、メイン画像が1枚だとできないことに気付き今回の方法に変更した経緯があります。
もしスライダーのようなアニメーション動作をさせたい場合は複雑になるのは必至なので、大人しくSlickなどのプラグインを使った方が良いかもしれません。
最後に全載せして終わります↓

  
    <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>画像切り替え</title>
      <style>
        /* メイン画像 */
        .bl_mediaCat_img {
          margin: 0 0 16px 0;
          overflow: hidden;
          padding-top: 65.755%;
          position: relative;
        }
        
        .bl_mediaCat_img img {
          -webkit-transform: translateY(-50%);
          -o-object-fit: cover;
          border-radius: 20px;
          height: 100%;
          left: 0;
          object-fit: cover;
          position: absolute;
          top: 50%;
          transform: translateY(-50%);
          width: 100%;
        }
        
        /* サブ画像 */
        .bl_mediaCat_imgWrapper ul {
          display: flex;
          justify-content: space-between;
          padding-left: 0;
          list-style: none;
        }
        
        .bl_mediaCat_imgItem {
          cursor: pointer;
          padding-top: 22.947%;
          position: relative;
          width: 22.947%;
        }
        
        .bl_mediaCat_imgItem img {
          -webkit-transform: translateY(-50%);
          -o-object-fit: cover;
          border: 1px solid transparent;/* ① */
          border-radius: 20px;
          height: 100%;
          left: 0;
          object-fit: cover;
          position: absolute;
          top: 50%;
          transform: translateY(-50%);
          width: 100%;
        }
        
        /* [.is_active]クラスが付与されたら、サブ画像にオレンジのボーダーを付ける */
        .bl_mediaCat_imgItem.is_active img {
          border: 1px solid #F7B500;
        }
      </style>
    </head>
    <body>
      <div class="bl_mediaCat_imgWrapper">
        <figure class="bl_mediaCat_img"><img src="https://picsum.photos/seed/picsum/1000/800"></figure>
        <ul>
          <li class="bl_mediaCat_imgItem"><img src="https://picsum.photos/seed/picsum/1000/800"></li>
          <li class="bl_mediaCat_imgItem"><img src="https://picsum.photos/seed/picsum/800/1000?grayscale"></li>
          <li class="bl_mediaCat_imgItem"><img src="https://picsum.photos/seed/picsum/1200/800?blur"></li>
          <li class="bl_mediaCat_imgItem"><img src="https://picsum.photos/seed/picsum/800/1200?grayscale"></li>
        </ul>
      </div>
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
      <script>
        // 画像切り替えクリックイベント
        $(window).on('load', function () {
          // 最初のliにis_activeを追加
          $('.bl_mediaCat_imgItem:first-of-type').addClass('is_active');/* ① */
        });
        
        $(function () {
          // サブ画像がクリックされた時
          $('.bl_mediaCat_imgItem img').on('click', function () {
            // クリックされたサブ画像のsrcを変数imgに代入
            let img = $(this).attr('src');/* ② */
            // サブの[.bl_mediaCat_imgItem.is_active img]から[.is_active]を削除(ボーダーが消える)
            $('.bl_mediaCat_imgItem').removeClass('is_active');/* ③ */
            // クリックされたサブ画像の親要素[.bl_mediaCat_imgItem]に[.is_active]を追加(ボーダーが付く)
            $(this).parent().addClass('is_active');/* ④ */
            // メイン画像を0.05秒かけてフェードアウト
            $('.bl_mediaCat_img img').fadeOut(50, function () {/* ⑤ */
              // メイン画像のsrcに、クリックされたサブ画像のsrcを読み込んでフェードイン
              $(this).attr('src', img).on('load', function () {/* ⑥ */
                $(this).fadeIn();/* ⑦ */
              });
            });
          });
        });
      </script>
    </body>
    </html>
  

人気記事忍者CODEさんのコーディング案件に挑戦してみた

人気記事WordPressのトップにHTMLページを表示させる方法