[jQuery] サムネイルをクリックするとメイン画像が入れ替わるレスポンシブ対応のギャラリーを作る
サムネイル画像をクリックすると、メインの大きい画像が入れ替わる定番のギャラリーを jQuery を使って作る方法です。現在メイン表示されている画像のサムネイルへのカレント機能と、レスポンシブ表示にも対応しています。
IE8+ / iOS8 / Android4.3 / その他のブラウザで動作確認済みです。最低限のシンプルなコードなのでカスタマイズもしやすいと思います。
サンプルデモ
横幅が狭くなった場合のサムネイル画像は、設定した min-width まで小さくなり、並びきらない場合は以下のように2段になって表示します。
HTML コード
画像をサムネイルサイズの画像と大きい画像と二種類用意します。
HTML はまず、サムネイル画像をリスト形式で記入し ID を #thumbnail と付けます。
サムネイルをクリックした際に、画像のリンク先を取得しメイン画像部分へ表示する仕組みのため、サムネイルのリンク先に大きい画像ファイルのパスを記入します。
メイン画像を表示する為の div 要素を空で記入し、#main_photo と ID をふります。サムネイルとメイン画像の記述を #photo_container という ID 名の div で囲みます。
<div id="photo_container"> <!-- #thumbnail --> <ul id="thumbnail"> <li><a href="image/1.jpg"><img src="image/thumb/1.jpg" alt="photo1" /></a></li> <li><a href="image/2.jpg"><img src="image/thumb/2.jpg" alt="photo2" /></a></li> : : </ul> <!-- /#thumbnail --> <!-- #main_photo --> <div id="main_photo"> </div> <!-- /#main_photo --> </div><!-- /#photo_container -->
CSS コード
このギャラリーをレスポンシブにする為のものと表示に必要なものだけを抜き出しました。
サムネイルの横並びには float を使っているため、親の ul 要素に overflow: hidden しています。img 要素はそれぞれ横幅を 100% にします。
メイン画像はクロスフェード表示するため一瞬の間2枚の画像を重ねて表示します。そのため、#main_photo img に position: absolute の指定をし、#main_photo に img の高さを指定しておきます。
メインで表示中の画像に対応するサムネイルの li 要素に .current というクラス名がつくため、カレント時の装飾を CSS 側で行います。
#thumbnail{ overflow: hidden; width: 100%; } #thumbnail li{ float: left; } #thumbnail li img{ width: 100%; opacity: 0.5; filter: alpha(opacity=50); } #thumbnail li.current img{ opacity: 1; filter: alpha(opacity=100); } #main_photo{ position: relative; height: 550px; } #main_photo img{ position: absolute; top:0; width: 100%; }
jQuery コード
jQuery 本体と以下のコードを head もしくは body 終了タグ直前に記入します。
5行目 maxWidth にギャラリー全体の親となる #photo_cotainer の max-width 値を記入、
6行目 thumbMaxWidth にサムネイル li 要素の max-width 値、7行目に min-width 値を記入します。
8行目 fade でフェードアウトのアニメーションスピードを設定できます。
細かい動作はコード内のコメントで説明しています。コメントをたくさん入れた為長くなってしまいましたが、コメントや改行などを削除すればそんなに長くないです。
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <script> // 横幅などの設定 var options = { maxWidth : 520, // #photo_container の max-width を指定(px) thumbMaxWidth : 80, // #thumbnail li の max-width を指定(px) thumbMinWidth : 60, // #thumbnail li の min-width を指定(px) fade : 500 // フェードアウトするスピードを指定 }; $(function(){ // 変数を作る var thumbList = $('#thumbnail').find('a'), mainPhoto = $('#main_photo'), img = $('<img />'), imgHeight; // 親ボックスと li 要素に max-width 指定 $('#photo_container').css('maxWidth', options.maxWidth); // li 要素の横幅の計算と指定 var liWidth = Math.floor((options.thumbMaxWidth / options.maxWidth) * 100); $('#thumbnail li').css({ width : liWidth + '%', maxWidth : options.thumbMaxWidth, minWidth : options.thumbMinWidth }); // 最初の画像の div#main_photo へ表示と current クラスを指定 img = img.attr({ src: $(thumbList[0]).attr('href'), alt: $(thumbList[0]).find('img').attr('alt') }); mainPhoto.append(img); $('#thumbnail li:first').addClass('current'); // メイン画像を先に読み込んどく for(var i = 0; i < thumbList.length; i++){ $('<img />').attr({ src: $(thumbList[i]).attr('href'), alt: $(thumbList[i]).find('img').attr('alt') }); } // サムネイルのクリックイベント thumbList.on('click', function(){ // img 要素を作り サムネイル画像からリンク・altの情報を取得・設定する var photo = $('<img />').attr({ src: $(this).attr('href'), alt: $(this).find('img').attr('alt') }); // div#main_photo へ 上で作った img 要素を挿入する mainPhoto.find('img').before(photo); // div#main_photo に先に表示されていた img 要素をフェードしながら非表示にし要素を消す、 mainPhoto.find('img:not(:first)').stop(true, true).fadeOut(options.fade, function(){ $(this).remove(); }); // 新しく表示した img の親 li へ .current を付け、 // 他の li 要素についていた .current を削除する $(this).parent().addClass('current').siblings().removeClass('current'); // 画像の親要素を現在表示中の画像の高さへ変更する mainPhoto.height(photo.outerHeight()); return false; }); // ウィンドウが読み込まれた時とリサイズされた時に // div#main_photo の高さを img の高さへ変更する $(window).on('resize load', function(){ mainPhoto.height(mainPhoto.find('img').outerHeight()); }); }); </script>
サンプルのコード
サンプルの全てのコードは以下のページで確認できます。
◆ gist:b5bb2a732fa48fdf3b7d
ギャラリーを複数設置する場合:2016/09/27追記
◆ レスポンシブギャラリーを複数設置したデモ|memocarilog
ギャラリーを1つのページ内に複数設置したい場合には、id で指定していた箇所を class に指定しなおす必要があります。CSS もそれに合わせたものに変更します。
1つめのギャラリー <div class="photo_container"> <!-- ,thumbnail --> <ul class="thumbnail"> <li><a href="image/1.jpg"><img src="image/thumb/1.jpg" alt="photo1" /></a></li> <li><a href="image/2.jpg"><img src="image/thumb/2.jpg" alt="photo2" /></a></li> : : </ul> <!-- /.thumbnail --> <!-- .main_photo --> <div class="main_photo"> </div> <!-- /.main_photo --> </div><!-- /.photo_container --> 2つめのギャラリー <div class="photo_container"> <!-- ,thumbnail --> <ul class="thumbnail"> <li><a href="image/1.jpg"><img src="image/thumb/1.jpg" alt="photo1" /></a></li> <li><a href="image/2.jpg"><img src="image/thumb/2.jpg" alt="photo2" /></a></li> : : </ul> <!-- /.thumbnail --> <!-- .main_photo --> <div class="main_photo"> </div> <!-- /.main_photo --> </div><!-- /.photo_container -->
複数設置する jQuery コード
コメント欄にも書きましたが、基本的に id 指定を class 指定に変更し、each メソッドで複数のギャラリーに対応できるようにします。
すべてのコードはこちらで確認できます → ◆ レスポンシブギャラリー複数設置 demoコード
$(function(){ $('.photo_container').each(function(){ var thumbList = $('.thumbnail', this).find('a'), mainPhoto = $('.main_photo', this), img = $('<img />'), imgHeight; $( this ).css('maxWidth', options.maxWidth); var liWidth = Math.floor((options.thumbMaxWidth / options.maxWidth) * 100); $('.thumbnail li', this).css({ width : liWidth + '%', maxWidth : options.thumbMaxWidth, minWidth : options.thumbMinWidth }); img = img.attr({ src: $(thumbList[0]).attr('href'), alt: $(thumbList[0]).find('img').attr('alt') }); mainPhoto.append(img); $('#thumbnail li:first', this).addClass('current'); : :
メイン画像とともにキャプションも表示するギャラリーを作る場合
コメントでキャプション表示を行う方法をご質問頂いたので、記事の追記としてまとめました。元(上記)のコードに data 属性を付け足してキャプションを表示するような方法となっています。
キャプション付きのギャラリーサンプル
◆ レスポンシブギャラリー(キャプション付き)デモ|memocarilog
キャプション付きにする追加 HTML コード
#thumbnail li 要素内 img 要素へ data 属性を追加します。ここでは「data-caption」という属性名にしました。data-caption 属性へキャプションのテキストを記入します。
<!-- #thumbnail --> <ul id="thumbnail"> <li><a href="image/1.jpg"><img src="image/thumb/1.jpg" alt="photo1" data-caption="1. ナッツの瓶詰め" /></a></li> <li><a href="image/2.jpg"><img src="image/thumb/2.jpg" alt="photo2" data-caption="2. 猫とおじいさん" /></a></li> : (略) : </ul> <!-- /#thumbnail -->
次に、キャプションを表示したい適当な場所へ、適当な空要素を記入し ID 名に caption と振ります。サンプルでは #main_photo の下へ p 要素を作りました。
<!-- #main_photo --> <div id="main_photo"> </div> <!-- #caption --> <p id="caption"></p>
キャプション付きにする追加 jQuery コード
キャプション表示を行うために追加したコード部分のみを抜き出しました。
7,8 行目のコードでキャプションに関する変数宣言の追加、21,22目のコードでページを開いた時に表示する最初のサムネイルのテキストの取得とキャプションの表示、34目のコードでサムネイルクリック時のテキストの入れ替えの処理を行います。
サンプルの全てのコードはこちらのページ「sample2_caption.html」で確認できます。
$(function(){ var thumbList = $('#thumbnail').find('a'), mainPhoto = $('#main_photo'), img = $('<img />'), imgHeight, // ↓ キャプションに関する変数を追加 caption = $('#caption'), captionText; : (略) : img = img.attr({ src: $(thumbList[0]).attr('href'), alt: $(thumbList[0]).find('img').attr('alt') }); mainPhoto.append(img); // 最初のキャプション取得と挿入 captionText = $(thumbList[0]).find('img').attr('data-caption'); caption.text(captionText); : (略) : thumbList.on('click', function(){ var photo = $('<img />').attr({ src: $(this).attr('href'), alt: $(this).find('img').attr('alt') }); // キャプション入れ替える caption.text($(this).find('img').attr('data-caption')); :
いつも参考にさせて頂いております。
メイン画像と一緒にキャプションを表示したいのですが、html,jsにどのように記述したら良いでしょうか。
クレア さま
ご参考ありがとうございます。ご質問の件を記事の追記としてまとめましたのでご確認下さい。
◆ メイン画像とともにキャプションも表示するギャラリーを作る場合
度々すみません。あと、最初のコードは連続してサムネイルをクリックした時に不具合があった為少しコードを書き直しています。キャプション付きのコードは書き直した後のコードなので、すべてこちらのコードを参考にして頂けると不具合が少ないかと思います。よろしくお願いします。
すばやく分かりやすく追記して頂き、特にjQueryコードが苦手な為、とてもたすかりました。本当にありがとうございました。
大変恐縮なのですが、もう一つだけ質問させてください。
サムネイル画像を左側、メイン画像を右側に並べて表示する為にはどのようにCSSを書き直したら良いでしょうか?
floatをかけたり、positionをなんとか移動しようとしたのですが、思う位置に来なかったり、動作がおかしくなったりして、どうしても上手くいきませんでした。初歩的な事でしたら申し訳ありません。
クレア さま
親の box の最大横幅を js 側で指定したりしていたため、レイアウトの変更がややこしくなっていました。わかりにくくてすみません…。
まず、js 内で #photo_container の max-width を設定していた部分を削除(81行目)して、CSS 側で #main_photo の max-width を設定します。その他の CSS 指定はコメントを付けて以下のアドレスへアップしたのでご確認下さい。
sample3_yoko_layout.html
HTML は特に変更なしで大丈夫だと思います。
私の知識不足でレイアウトの変更が出来なかったのですが、再度ご対応頂き、分かりやすいコメントを付けて頂けて大変たすかりました。今後もいろいろと参考にさせて頂き、勉強致します。本当にありがとうございました。
はじめまして。
キャプションつきの画像切替の方法を探していて、大変参考になりました。
ひとつ質問なのですが、切り替えた画像のキャプションの表示位置は、
最初に読み込まれた画像の高さに絶対位置で指定されてしまうのでしょうか?
縦サイズがまちまちの画像が表示されるギャラリーページを作っているのですが、
最初に読み込まれる画像よりも縦に大きい画像だと、キャプションの位置は変わらずに、
画像の下に埋もれてしまいます。
縦に小さい画像だと逆に画像との間にスペースができます。
これを、呼び出す画像の縦サイズに合わせてキャプション位置を上下させたいのですが、
これは不可能でしょうか?
あれこれといじってみたのですが、知識不足でどうしても解決できませんでした。
もしよろしければご教授いただけると幸いです。
よろしくお願いします。
H.Y さま
はじめまして。ご参考下さりありがとうございます。
ご質問の件ですが、
メイン画像の親要素( div#main_photo )の高さを、最初に読み込んだ時に表示していた画像の高さに固定していたためにそのような状態になっていました…。
サムネイルをクリックした時に、メイン画像に表示される画像の高さへ親要素の高さが変更されるように、コードを一行追加いたしました。
以下のページの、
◆sample2_caption.html
118行目の箇所( return false; の前の行)へ mainPhoto.height(photo.outerHeight()); というコードを追加して頂ければ大丈夫だと思います。よろしくお願いいたします。
早速のご返答、ありがとうございます。
コードを追加したら大丈夫でした!!
不躾な質問に丁寧にご対応いただきまして、大変感謝します。
また色々と参考にさせていただきたいと思います。
ありがとうございました。
okinawa さま
お返事おそくなりすみません。
ご質問の件ですが、マルチで使用することを想定せずに作ったものですが、
クラスで指定し、each メソッドで回せば複数設置もできるかもしれません…。
また時間がある時に、複数設置する方法も記事に追記できるとよいなと思います。
お忙しい中、ご返事ありがとうございます!
なるほど!eachメソッドで回す方法があるんですね!
for文ばっかり調べてました…w
jQuery初心者で不躾な質問にもかかわらず、
ご回答頂き、感謝致します。
本当にありがとうございます!^^
サイト応援していますので、がんばって下さい!^^
初めまして!
こちらのサイト、とても参考にさせていただいています。
非常に初歩的な質問で申し訳ないのですが・・・
縦サイズ・横サイズ全てバラバラの画像を使って、ギャラリー表示をしたいと考えています。
サムネイルの画像の大きさを正方形にトリミングして表示させ、
さらにメイン画像の最大幅・最大高さを固定してしまって、
その中で画像の大きさを変えたい、と思っているのですが、
どのようにすればよいでしょうか?
自分で色々とcssをいじってみたのですが、どうにもうまくいかず・・・
アドバイスいただけるとありがたいです。
よろしくお願いいたします。
yukie さま
初めまして。ご参考ありがとうございます。
現在はメイン画像の高さを jQuery で制御していますが、それをしないようにということでしょうか…?
もしそういうことなら、以下のページのコードの
https://gist.github.com/SaoriMiyazaki/b5bb2a732fa48fdf3b7d#file-gistfile1-html
102行目 mainPhoto.height(photo.outerHeight());
107行目 mainPhoto.height(mainPhoto.find(‘img’).outerHeight());
を削除して下さい。そうすれば、最大の高さはCSS側の設定が有効になるかと思います。
はじめまして。とても素敵なサムネイル付きギャラリーで参考にさせて頂いています。jQuery超初心者のため、お聞かせいただきたいことがございます。
こちらのギャラリーを同一ページで複数設置したいのですが、idの変更で、複数表示までは出来ましたが、一つをクリックすると他のギャラリー全ての画像と連動して動いてしまいます。eachメソッドを使えば、という内容の事を先のご質問で書いておられましたが、どのように記述すべきか調べたのですが、分かりません。宜しければ教えていただきたいです。
yamada さま
はじめまして。ご参考ありがとうございます。
each メソッドの使い方をコメント欄にてお伝えするのは少々難しいと思いますので、他の方の記事をご紹介させて頂きますね。
each メソッドについてはこちらの記事が分かりやすいと思います。
jQueryのeachの仕組みを徹底的にわかりやすく解説してみた。 · DQNEO起業日記
jQuery 自体のことはこちらの記事がとてもわかりやすいと思います。
CSSは分かるけど jQuery は苦手 … という人が jQuery に親しんでくれるといいなーと思って書きました
初めまして!
こちらのギャラリー、参考にさせて頂いてます。
非常に初歩的な質問で申し訳ないのですが、サムネイルとメイン画像の上下を入れ替えたいのですが、どのようにすれば良いでしょうか?
お手数ですが、ご教授いただければ幸いです。
satou さま
はじめまして。ご参考ありがとうございます。「<div id="main_photo"></div>」の位置を変更していただくと、上下入れ替わると思います。
よろしくお願いいたします。
はじめまして。
とてもシンプルでぜひ使わせていただきたいと思っているのですが、
autoplayというのは可能でしょうか。
自力で追記できればよいのですが、度量不足で・・・。
ご教授いただけると幸いです。よろしくお願いいたします。
miz さま
はじめまして。
こちらの記事のコードにautoplayなどの機能をつけたギャラリーの作り方を紹介した記事「[jQuery] サムネイル付きのレスポンシブなスライドショーを作る方法」をご参照いただけると幸いです。
デモ「レスポンシブスライドショーデモ demo|memocarilog」
よろしくお願いいたします。
ありがとうございました。
思ってるとおり!の機能でした。お手数おかけいたしました~。
初めまして。とても親切なブログで勉強させてもらっています。
上記のシンプルなギャラリーを使わせていただいているのですが、
どうしてもメイン画像にサムネイルが被ってしまう時があります。(5回に2回は)
上記でも訂正したとのことでしたが、勉強不足のためどこを直せばサムネイルの位置が固定できるのかわかりません。
メイン画像を上に配置して、サムネイルを下に配置しています。
時々、メイン画像がフロート状態になって、サムネイルが隠れてしまいます。
お手数ですが、ご教授いただけるとさいわいですm(--)m
ちゃんと読んでなくてスイマセン・・・。
102行目 mainPhoto.height(photo.outerHeight());
107行目 mainPhoto.height(mainPhoto.find(‘img’).outerHeight());
をコメントアウトしたら動きました(^^)
ありがとうございました!!
mike さま
ご参考ありがとうございます。無事に動いたようでよかったです。
よろしくお願いします。
お世話になります、参考にさせて頂いております。
早速ご質問ですが、同じページ内に二つのギャラリーを表示させようとした場合、どこを調整すれば宜しいのでしょうか。
いくつか思うようにトライしてみたのですが、どうしても2つになりませんでした。
ちなみに今作業しているのは、左にmain_photoを置いて、右に2列×4行の8個のサムネールを置いております。
これを1ユニットとして、2ユニット置きたいと思っております。
あまりJQueryには明るくないのですが、ご教授頂ければ幸いです。
nicnic さま
このコードだけでは複数のギャラリーを正常に動かすことはできないので、
先のコメントの返信でもお伝えしていますが、IDで記述しているところをclassに変更し、eachメソッドというものを追加する必要があります。
具体的にどの部分なのかをコメント欄でお伝えするのは少々難しいです…。
nicnic さまはJQueryには明るくないとのことですので、複数処理に対応したプラグインなどを探された方が早いかもしれません。
よろしくお願いいたしますm(_ _)m
初めまして、最近このページを参考にさせていただいております。
質問なのですが、画像を表示させる枠内に様々な大きさのものを表示させたいと考えています。
画像の横幅が枠より小さい場合は原寸大で。枠より大きい場合は枠内に横幅おさまる様に縦横比例縮小させるということは可能でしょうか。
ちなみに、キャプション付きのものを基準に作成したいです。
お手数おかけしますが、ご教授いただけると幸いです。
初めまして。ご参考ありがとうございます。
現在のコードだと、jQuery側で高さを指定しているので、高さ指定している以下の二行を削除するかコメントアウトし、
#main_photo へ CSSで適当な高さを指定し、
#main_photo img の width: 100%; を削除、 max-width: 100%; max-height:100%; を追加指定してみるのはいかがでしょうか?
お世話になっております。
教えていただいた方法で、解決しました!
お忙しい中、返答有難うございました。
初めまして。お世話になっております。
サムネ付きのギャラリーを探していて、このサイトにたどり着きました。
シンプルでオシャレで素敵なギャラリーですね。
早速、サイトに導入させて頂きましたが、1点だけ不明な個所がありました。
【ギャラリーを複数設置する場合:2016/09/27追記】
ギャラリーを複数設置しましたが、ページを開いた際にサムネがアクティブになりません。(ページを開いた際に1枚目のサムネが透過してない状態)
デモページでもアクティブになっていませんが、これはどうやってアクティブにすればよろしいでしょうか。
お忙しい中恐縮ですが、お時間がある際にお教え頂ければ幸いです。どうぞよろしくお願い致します。
お世話になります。
おかげさまで解決しました!
【解決法】
mainPhoto.append(img);
$(‘#thumbnail li:first’).addClass(‘current’);
↓↓↓
mainPhoto.append(img);
$(‘.thumbnail li:first’).addClass(‘current’);
スタイルシートの内容を変更したため、jQuery コードも変えてあげる必要があった訳ですね。ありがとうございました^^
uta さま
返信が遅くなり申し訳ありません。
解決したとのことで何よりです。ご連絡ありがとうございました。
初めまして。
サムネ付きのギャラリーを探していて、このサイトにたどり着きました。
素晴らしい内容にてとても助かりました。
実装させて頂きましたところ、問題が出て、格闘したのですが当方では解決ができませんでしたのでご迷惑を承知でコメントさせて頂きました。
ほぼそのままのコードを使用しているのですが、違うところは高さが二種類の画像を混在させている点です。(サムネイルは同じサイズで揃えています)
レイアウトは左に画像、その下にキャプション、右にサムネイルを並べ、要素をfloatで並べています。
画像を切り替えると画像の高さに合わせて「main_photo」の高さが可変するようにしたいのですが、Chromeだけ高さを取得できずに下の要素に重なってしまいます。サムネイルを再度クリックするとサイズを取得して正常な表示になります。
IE、Firefox、Safariでは正常に動作します。
こちらに掲載されているサンプルも同じ動作になっています。
何か解決法はありませんでしょうか。
年月の経つ記事にコメント差し上げて申し訳ありません。
ご回答頂けましたら本当に助かります。
何卒宜しくお願い致します。
KO さま
はじめして!ご参考いただきありがとうございます。
thumbList.on(‘click’, function(){
の箇所を以下のようにしていただいてはどうでしょうか??
全体のコードを以下に貼っておきました
https://gist.github.com/SaoriMiyazaki/134a4ea6194a3fa2f97a74aa300a6e04
saori様
先日は迅速なご対応ありがとうございました!
お返事が遅くなり大変失礼致しました。
早速試してみたのですが、うまく機能しませんでした…。
お問い合わせさせて頂いた時と同じく、Chromeだけ高さを取得できずに下の要素に重なってしまいます。
横長画像と縦長画像を混在させたギャラリー(画像の横は統一)で、読み込み時に縦長画像の場合は機能するのですが、次の画像に切り替えると縦長画像の場合は下の要素に重なってしまいます。横画像の表示は問題ありません。
デフォルトの高さは横長画像の高さにmin-heightで設定しております。
縦長画像を表示する場合は伸縮するようにしたいです。
キャプションが出るようにもしているので、その具合でこちらがミスをしているのかもしれません…
大変恐れ入りますが、キャプション表示仕様のコードをアップして頂けませんでしょうか。
お手数お手間をお掛けしまして申し訳ございません。
何卒宜しくお願い致します。
はじめまして。
今回、サムネイル画像をクリックしたときにキャプション付きでメイン画像が切り替わる処理を探していたところこのページにたどり着きました。
とっても丁寧で分かりやすい記事をありがとうございます。
saoriさんはjQueryを使っておられますが、私は今回jQueryを使用せずシンプルなJavaScriptだけで動かしたいと考えています。
その場合どのような書き方になりますでしょうか。
お忙しいところすみませんが、教えていただけると幸いです。
よろしくお願いいたします。
mk さま
お返事おそくなりすみません。。。ご参考いただいてありがとうございます!
そうですね、JavaScript だけでということだと、この記事の jQuery がおこなっている挙動を 素の JavaScript で再現する必要があるかと思います。「脱jQuery」などでぐぐってみて出てくる記事などで差し替えるコードを調べてみるといいかもしれませんね。