カテゴリー
CSS HTML jQuery Webサイト作成

ギャラリーページ

こんにちは、エムケーワイです。

またまた投稿間隔があいてしまいました。その間にプロ野球開幕に続き、Jリーグが再開されましたね。

今回から3回に分けてギャラリーページとその応用にトライしようと思っているのですが、その実現方法を調べたり、使用する画像を用意するのに予想外に手こずっていました^_^;

まずは第1弾ということで、複数枚の画像をタイル状に並べて表示するギャラリーページを作ります。そして、それぞれの画像をクリックすると、「画像クリックで拡大画像をモーダル表示する」でやったように拡大画像をモーダル表示するようにします。

では、早速結果を見ていただきます。

    今回は下記の処理が肝になります。

    • ギャラリーに表示する画像のファイル名やタイトル等をJSON形式の外部ファイルから取得する。
    • ギャラリー部分のHTMLコードをjQueryで生成する。
    • ImagesLoaded“というJavaScriptライブラリを使って、ギャラリーの全画像が読み込まれたことを確認してから画像を表示する。
    • Masonry“というJavaScriptライブラリを使って、ギャラリーの画像をレイアウトする。

    結構盛り沢山でかなり長くなりそうですが、実現方法を説明して行きます。

    目次 [閉じる]
    1. HTMLコード
    2. JSONファイル
    3. JavaScriptライブラリの読み込み
    4. jQueryコード
    5. CSS設定

    1. HTMLコード

    ギャラリーに関するHTMLコードで、カスタムHTMLで記述するのは下記のみです。

    ギャラリーのコンテンツに関するHTMLコードは、JSONファイルから取得した情報に基づき、jQueryでulタグ内に追記します。

    <div class="mkyGalleryContainer">
        <ul class="mkyGallery"></ul>
    </div>
    • “mkyGalleryContainer”がギャラリー全体を含むコンテナになります。
    • ギャラリーのコンテンツをリスト要素として追加するために、空のulタグを用意しています。

    2. JSONファイル

    JSONは”JavaScript Object Notation”の略で、JavaScript以外の世界でも使われているデータ形式です。

    全体が”[“と”]”で囲まれた配列で、配列の各要素は”{“と”}”で囲まれたオブジェクトです。オブジェクト内にはプロパティと値を持つデータが含まれます。

    今回使用したJSONファイルは”gallery.json”というファイル名で、子テーマフォルダ(twentytwenty_ch)内のフォルダgalleryに置かれています。

    gallery.jsonの中身は下記のようになっています。

    [
      {
        "title": "Night View",
        "category": "HongKong",
        "images": {
          "thumb": "/wp-content/themes/twentytwenty_ch/gallery/images/thumb-H-8.jpg",
          "large": "/wp-content/themes/twentytwenty_ch/gallery/images/large-H-8.jpg"
        }
      },
      {
        "title": "Victoria Harbor",
        "category": "HongKong",
        "images": {
          "thumb": "/wp-content/themes/twentytwenty_ch/gallery/images/thumb-H-4.jpg",
          "large": "/wp-content/themes/twentytwenty_ch/gallery/images/large-H-4.jpg"
        }
      },
      { ... }
    ]
    • titleは画像のタイトルで、拡大画像がモーダル表示された際に表示されます。
    • categoryは画像のカテゴリーで、”HongKng”、”Shenzhen”、”Vietnam”、”Flowers”、”Fireworks”の5つのカテゴリーが存在します。カテゴリーは今回は使用していませんが、第3弾のカテゴリー別表示で使用する予定です。
    • imagesには、ギャラリー表示の際のサムネイル画像のURLと、モーダル表示の際の拡大画像のURLが含まれます。

    画像が多すぎると表示に時間がかかるので、今回は各カテゴリー4種類ずつ、合計20種類の画像を用意しました。

    第2弾では画像を大幅に増やし、追加ボタンをクリックすることで、ギャラリーに所定枚数ずつ追加表示していく機能を実装する予定です。

    なお、使用している画像は全て私自身が撮影したものです。

    余談ですが、”images”の”}”の後ろにカンマ”,”をつけないようにしましょう!

    最初カンマをつけていたために、gallery.jsonの読み込みは行うものの、その後の処理が行われず、原因を特定するのに非常に苦労しました^_^;

    オブジェクト内の最後の要素なので、カンマは不要ですね。

    3. JavaScriptライブラリの読み込み

    先に紹介した2つのJavaScriptライブラリ(ImagesLoadedMasonry)を読み込みます。

    どちらもCDN経由で読み込ませることができますが、今回はそれぞれのサイトからダウンロードしたjsファイルを読み込むことにしました。

    3-1. ImagesLoadedのダウンロード

    1) ImagesLoadedのサイトにアクセスします。

    2) 下にスクロールし、jsファイルをダウンロードします。今回はminifyされたファイルをダウンロードしました。

    3-2. Masonryのダウンロード

    1) Masonryのサイトにアクセスし、右サイドメニューの”Download”をクリックします。

    2) jsファイルをダウンロードします。今回はminifyされたファイルをダウンロードしました。

    3-3. jsファイルの読み込み

    functions.phpに下記のコードを追加し、ダウンロードした2つのjsファイルを読み込みます。

    なお、2つのjsファイルは、子テーマフォルダ(twentytwenty_ch)内のフォルダgalleryに置かれています。

    また、下記コードは本ページにのみ適用されます。

    wp_enqueue_script( 
        'masonry-script', 
        get_stylesheet_directory_uri() . '/gallery/masonry.pkgd.min.js',
        array(),
        '4.2.2',
        true
    );
    wp_enqueue_script( 
        'imageloaded-script', 
        get_stylesheet_directory_uri() . '/gallery/imagesloaded.pkgd.min.js',
        array(),
        '4.1.4',
        true
    );

    4. jQueryコード

    今回作成したjQueryコードは下記になります。

    ちょっと長くなったので、いくつかに分けて説明します。

    jQuery(function() {
        jQuery('.mkyGallery').each(function() {
            var _gallery = jQuery(this),	// ギャラリーオブジェクト
                jsonData = [],              // JSONデータ
    	    galleryW = _gallery.width(),    // ギャラリー領域の幅
    	    imageW = 300,		// 画像の幅
    	    gutterW;			// gutterの幅
    			
    	// gutterの幅を算出
    	if (galleryW > 900) {
    	    gutterW = Math.floor((galleryW - imageW * 3) / 2);
    	} else if (galleryW > 600) {
    	    gutterW = galleryW - imageW * 2;
    	} else {
    	    gutterW = galleryW - imageW;
    	}
    		
    	// Masonry初期設定
            _gallery.masonry({
                columnWidth: 300,
                gutter: gutterW,
                itemSelector: '.mkyGalleryItem'
            });
    
            // JSONデータを取得し、ギャラリーを生成する
            jQuery.getJSON('/wp-content/themes/twentytwenty_ch/gallery/gallery.json', function(data) {
                // 取得した JSON データを格納
                jsonData = data;
                // ギャラリーのHTMLコードを生成し、画像を表示する
                createHTML();
            });
    
            // HTMLコードを生成しギャラリーを表示する
            function createHTML() {
                var elements = [];
    
                jQuery.each(jsonData, function (i, item) {
                	// HTMLコード(文字列)を生成する
                    var htmlCode =
                            '<li class="mkyGalleryItem onLoading">' +
                            '<a class= "mkyJsModalOpen" href="' + item.images.large + '">' +
                            '<img src="' + item.images.thumb + '" alt="">' +
                            '</a>' +
                            '<div class="mkyModal mkyJsModal" style="display: none;">' +
                            '<div class="mkyModalBG"></div>' +
                            '<div class="mkyModalContent">' +
                            '<figure>' +
                            '<img src="' + item.images.large + '" alt="">' +
                            '<span class="caption">' +
                            '<b class="title">' + item.title + '</b>' +
                            '</span>' +
                            '<button class="mkyJsModalClose">×</button>' +
                            '</figure>' +
                            '</div>' +
                            '</div>' +
                            '</li>';
                    // HTMLコード(文字列)をDOM要素化し、配列に追加
                    elements.push(jQuery(htmlCode).get(0));
                });
    
                // DOM要素の配列をギャラリーに挿入しMasonryを実行
                _gallery
                    .append(elements)
                    .imagesLoaded(function() {
                        jQuery(elements).removeClass('onLoading');
                        _gallery.masonry('appended', elements);
    
                    });
    
                // 画像のモーダル表示		    
                jQuery('.mkyGalleryItem').on('click',function(){
    	        jQuery(this).find('.mkyJsModal').fadeIn();
    		return false;
                });
                jQuery('.mkyJsModalClose').on('click',function(){
    	        jQuery(this).parents('.mkyJsModal').fadeOut();
    		return false;
    	    });
            }
        });
    });

    4-1. 全体の流れ

    1. クラス”mkyGallery”を持つオブジェクトに対して処理を行います。クラス”mkyGallery”を持つオブジェクトは一つしかありませんが、複数ある場合にも対応できるようeach()メソッドを使っています。
    2. 変数の宣言、初期化を行います。
    3. Masonryのガター(gutter)の幅の算出と初期設定を行います。
    4. JSONファイル内のデータを取得し、ギャラリーを生成します。
    5. ギャラリーのHTMLコードを生成し、ギャラリー内の画像の配置、表示を行う処理を関数化します。
    6. 5の関数内で画像のモーダル表示も行います。

    4-2. 変数の宣言、初期化

    各変数の意味は下記の通りです。

    変数意味
    _galleryクラス”mkyGallery”を持つjQueryオブジェクト
    jsonDataJSONファイル内のデータを格納する配列
    galleryW_galleryの幅
    imageWギャラリーに表示される画像の幅
    今回は300としています。
    gutterWギャラリーに表示される画像間の隙間(gutter)の幅
    galleryWに応じて計算で求めます。

    4-3. Masonryの初期設定

    1. ギャラリーの列数に応じてMasonryのガター(gutter)の幅を算出します。
      ギャラリーの列数は下記の通りです。
         galleryW > 900:3列
         galleryW > 600:2列
         gallery <= 600:1列
    2. Masonryの初期設定を行います。
         columnWidth:カラム(画像)の幅を指定します
         gutter:カラム間の隙間(gutter)の幅を指定します
         itemSelector:要素のセレクターを指定します。
            今回はこの後生成されるliタグのクラス”mkyGalleryItem”を指定しています。

    4-4. JSONデータの取得とギャラリー生成

    1. jQuery.getJSON()メソッドを使ってgallery.json内のデータを取得します。取得したデータは、引数dataとして取得後に実行される関数に渡されます。
    2. 変数jsonDataに1で取得したデータ(data)を代入します。
    3. ギャラリーのHTMLコードを生成し、画像を表示する関数createHTML()を呼び出します。

    WordPressでは、getJSON()メソッドに渡すJSONファイルのURLは”/wp_content/~”で指定するようです。試行錯誤の結果です^_^;

    4-5. HTMLコードの生成と画像の配置・表示

    HTMLコードを生成する処理とギャラリー内に画像を配置、表示する処理は関数化しています。この関数が呼び出される回数は、本ページでは1回のみですが、第2弾、第3弾では複数回呼び出されることを想定してのものです。

    4-5-1. HTMLコードの生成

    gallery.jsonから取得したデータは配列になっています。jQuery.each()メソッドで、この配列内の各要素に対してHTMLコードを生成します。配列の各要素は引数itemとしてeach()メソッド内の関数に渡されます。

    1. 変数htmlCodeに生成するHTMLコードを文字列として代入します。
      ギャラリー内のコンテンツはolタグ内のクラス”mkyGalleryItem”および”onLoading”を持つli要素で、これがMasonryのセレクターになります。
      詳細は省略しますが、li要素内では、ギャラリーに表示されるサムネイル画像やモーダル表示される拡大画像、画像のタイトルがgallery.json内のプロパティを使って”item.images.thumb”、”item.images.large”、”item.title”で指定されます。
    2. htmlCode(文字列)をDOM要素化して配列elementsに追加します。
      配列elementsに要素を追加する際はpush()メソッドを使います。
      また、”jQuery(htmlCode)”によって文字列をjQueryオブジェクトに変換し、get(0)メソッドで先頭のDOMエレメント(li要素)を取得します。

    クラス”onLoading”は画像がロード中であることを示します。ロード中はCSS設定で非表示となります(“opacity: 0”)。

    今回jQuery(htmlCode)内には1つのli要素しかありませんが、jQueryオブジェクト内に複数の要素が含まれる場合は、get()メソッドにそれぞれのインデックスを渡すことで各要素を取得することができます。

    4-5-2. 画像の配置、表示

    ギャラリーの画像の配置、表示は_galleryのメソッドを使って実行します。このとき、ImagesLoaded、Masonryを使用します。

    1. append()メソッドでelements(DOM化したHTMLコード)を追加します(ul要素内に追加されます)。
    2. imagesLoaded()メソッドで全画像の読み込みが完了後、引数の関数を実行します。以下の3および4は引数の関数内で実行される処理です。
    3. elements内のHTMLコードから、画像がロード中であることを示すクラス”onLoading”を削除します。
    4. masonry()メソッドを使うことで、各画像の位置が自動的に計算され配置されます。masonry()メソッドの第1引数”appended”により、第2引数elements内の各要素が末尾に追加されていきます。

    4-5-3. 画像のモーダル表示

    拡大画像のモーダル表示については、詳細な説明は割愛します。「画像クリックで拡大画像をモーダル表示する」をご参照ください。

    1. ギャラリーのサムネイル画像がクリックされると、拡大画像をモーダル表示します。
    2. 拡大画像表示時に×ボタンがクリックされると、モーダル表示を終了します。

    画像のモーダル表示に関する処理は、ギャラリーの作成・表示とは独立していると考えたので、当初jQuery(‘.mkyGallery’).each(function() {})の外側に置いていたのですが、サムネイル画像をクリックするとaタグのhrefで指定された画像が表示され、モーダル表示されませんでした。

    jQuery(‘.mkyGallery’).each(function() {})の内側、関数createHTML()の外側に配置しても同様で、最終的に関数createHTML()内の最後尾に配置すると、意図通りにモーダル表示できるようになりました。

    クリックの対象となる要素が、createHTML()によってHTMLコードが生成された後でないと存在しないからでしょうか?

    この辺の依存関係が分かる方は、ご教授いただけると幸いです。

    5. CSS設定

    /*
    * Gallery
    */
    .mkyGalleryContainer {
        margin: auto;
        padding: 10px 10px;
        width: 100%;
    }
    
    .mkyGallery {
        margin: 0 !important;
        padding: 0 !important;
    }
    
    .mkyGalleryItem {
        list-style: none;
        margin: 10px 0 0 0;
    }
    .mkyGalleryItem.onLoading {
        opacity: 0;
    }
    .mkyGalleryItem a {
        display: block;
    }
    
    /*
    * 画像をモーダル表示
    */
    .mkyModal {
        display: none;
        width: 100%;
        height: 100%;
        position: fixed;
        top: 0;
        left: 0;
        z-index: 100;
    }
    
    .mkyModalBG {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(220,20,60,0.5);
    }
    
    .mkyModalContent {
        position: absolute;
        top: 5%;
        left: 5%;
        width: 90%;
        height: 90%;
        background-color: transparent;
        vertical-align: top;
    }
    
    .mkyModalContent img {
        position: absolute;
        max-width: 100%;
        max-height: 100%;
        top: 50%;
        left: 50%;
        transform: translate(-50%,-50%);
    }
    .mkyModalContent .title {
        display: inline-block;
        position: relative;
        padding: 2px 5px;
        background-color: black;
        color: white;
        font-weight: bold;
        z-index: 200;
    }
    .mkyModalContent button {
        position: absolute;
        top: 20px;
        right: 20px;
    }
    
    a img:hover {
        opacity: 0.7;
    }

    CSS設定では、説明が必要なものはほとんどないかと思いますので、ポイントだけ説明します。

    • クラス”mkyGallery”に対しては、親テーマ(twemtytwenty)がulに対して設定してるmarginとpaddingを上書きしています。
    • クラス”mkyGalleryItem”に対し、画像ロード中(クラス”onLoading”が設定されている)は非表示(“opacity: 0”)としています。
    • 画像のモーダル表示に関する設定は、「画像クリックで拡大画像をモーダル表示する」をご参照ください。
      ただし、クラス”title”に対する設定は今回追加したもので、画像のタイトル表示に関する設定を行っています。
      また、クラス”mkyModal”に対する設定でwidth、heightをそれぞれ100vw、100vhから100%に変更しました。これは、従来の設定では拡大画像の表示位置がウィンドウの上下左右中央から若干ずれるためです。

    スマホでモーダル表示をすると、全画面表示にならず、サムネイル画像上に背景と拡大画像(実際には縮小画像ですね^_^;)が表示されるかもしれません(Firefoxの開発ツールで確認)。

    これは、スマホの場合、Masonryにより親要素であるli要素にtransformが設定され、クラス”mkyModal”に対する”position: fixed”が効かなくなるための様です。ブラウザによって挙動が異なるかもしれませんが…

    対策は今後考えます。

    いかがでしたでしょうか?

    冒頭にも書きましたが、今回はJSONファイルからのデータの取得や、jQueryによるHTMLコードの作成など新しいことに調整んした結果、かなり苦労し途中で挫折しそうになりました(涙)

    また、ImagesLoaded、Masonryという2つのJavaScriptライブラリを使って、便利さを体感することはできたのですが、正直言ってまだ使い方が十分理解できていません…

    この後ギャラリーページ第2弾では、画像の種類を増やし、追加ボタンをクリックすることで、ギャラリーに所定枚数ずつ追加表示していく機能を、第3弾ではカテゴリー別に表示する機能を実装する予定です。

    また苦労すると思いますが、出来るだけ早く備忘録を投稿できるよう頑張ります!

    最後までお読みいただきありがとうございました。