ライトボックス Luminous Lightbox の使い方
Luminous はとても軽量でシンプルな jQuery に依存しない画像用ライトボックスプラグイン(JavaScript)です。
以下は Luminous Lightbox(v2.3.5/2021-08-03)の基本的な使い方や、ギャラリー表示やキャプションの表示方法、画像枚数と現在の画像位置(インデックス)の表示、webpack でのバンドル、WordPress で表示する方法などの解説(覚書)です。
Luminous Github:https://github.com/imgix/luminous
作成日:2021年9月29日
インストール
Luminous はダウンロードして読み込むか、npm などを使ってインストールすることができます。
ダウンロード
https://github.com/imgix/luminous の右上の「Code」をクリックして「Download ZIP」をクリックするか、本文中(Installation > Manual) の Download リンクをクリックすると luminous-main.zip という ZIP ファイルをダウンロードできるので、保存して解凍します。
解凍したフォルダ(luminous-main)の中の dist 内の以下の JavaScript と CSS ファイルを使います。
- luminous.min.js
- luminous-basic.min.css
CSS(luminous-basic.min.css)は head 内で読み込みます。「path/to/」の部分は適宜変更します。
<head> ・・・ <link rel="stylesheet" href="path/to/luminous-basic.min.css"> ・・・ </head>
JavaScript は body の閉じタグの直前などで読み込みます。
<script src="path/to/luminous.min.js"></script> ・・・ </body>
luminous.min.js にはソースマップの記述(//# sourceMappingURL=luminous.min.js.map)が最後にあるので、オプションで(必要に応じて)ソースマップファイル(luminous.min.js.map)を luminous.min.js と同じ階層に配置します(読み込む必要はありません)。
WordPress での読み込み
以下は WordPress で使う場合の読み込みの例です。「path/to/」の部分は適宜変更します。
10 行目と18行目は更新時にキャッシュをクリアするための記述ですが、この場合は省略しても良いかと思います。11行目はスクリプトを </body> 終了タグの前に配置するために true を指定しています。
function add_my_styles_and_scripts() { ・・・その他の読み込み・・ //JavaScript の読み込み wp_enqueue_script( 'luminous-js', get_theme_file_uri( '/path/to/luminous.min.js' ), array(), //依存するスクリプトはなし filemtime( get_theme_file_path( '/path/to/luminous.min.js' ) ), true //</body> 終了タグの前に配置 ); //CSS の読み込み wp_enqueue_style( 'luminous-style', get_theme_file_uri( '/path/to/luminous-basic.min.css' ), array(), //依存するスタイルシートはなし filemtime( get_theme_file_path( '/path/to/luminous-basic.min.css' ) ) ); } add_action('wp_enqueue_scripts', 'add_my_styles_and_scripts');
npm
npmコマンドを使ってインストールする場合はプロジェクトのフォルダで以下を実行します。
npm install luminous-lightbox
webpack
以下は webpack を使ってバンドルする場合のエントリポイントでの記述例です。CSS をバンドルする場合は CSS ローダーや style ローダー(必要に応じて MiniCssExtractPlugin)が必要です。CSS をバンドルしない場合は、別途 head 内で読み込みます。
//Luminous と LuminousGallery(ギャラリー表示用)のインポート(ES6) import { Luminous, LuminousGallery } from 'luminous-lightbox'; /* 以下は require を使って読み込む場合 const Luminous = require('luminous-lightbox').Luminous; const LuminousGallery = require('luminous-lightbox').LuminousGallery; */ //CSS のインポート(CSS ローダーが必要) import 'luminous-lightbox/dist/luminous-basic.min.css';
関連ページ:webpack の基本的な使い方
Luminous の使い方
基本的な使い方は JavaScript で Luminous を初期化し、HTML でライトボックス表示する画像を任意のクラス名を設定した a 要素で囲み、href 属性に拡大表示(ポップアップ)する画像のパスを指定します。
画像を a 要素で囲むことが多いですが、画像以外の要素を囲んでその要素をクリックして画像を表示することもできます(アイコンをクリックして表示)。
Luminous にはそのページで1つの画像のみに適用する方法(単体表示)と複数の画像に適用する方法(ギャラリー表示)があります。
単体表示
対象の img 要素を任意のクラス名(以下の場合は luminous)を設定した a 要素で囲みます。a 要素の href 属性には拡大表示する画像のパスを指定します。
以下の場合、01-w600.jpg は表示画像(サムネイル)で、01-w1800.jpg は拡大表示する画像です(表示画像と拡大画像に同じ画像を指定することもできます)。パスは適宜環境に合わせて変更します。
<a class="luminous" href="../img/01-w1800.jpg"> <img src="../img/01-w600.jpg" width="300" height="185" alt="Lotus"> </a>
JavaScript では querySelector() などを使って任意のクラス名(この例の場合は luminous)を設定した a 要素(trigger element)を取得して、new Luminous() の引数に渡して初期化します。
そのページに対象の要素がない場合は、初期化を行わないようにするため、querySelector() の戻り値が null でない場合にのみ初期化するようにしています。
//luminous クラスを指定した a 要素を取得 const luminousElem = document.querySelector('.luminous'); //上記で要素が取得できていれば Luminous を初期化 if( luminousElem !== null ) { new Luminous(luminousElem); }
new Luminous() の第1引数には DOM 要素を指定する必要があります。querySelector() は一致する要素がない場合は null を返すので、一致する要素がない場合は new Luminous() に null が渡されて「Uncaught TypeError: `new Luminous` requires a DOM element as its first argument.」のようなエラーが発生します。
複数画像の単体表示
Luminous には複数の画像をライトボックス表示するためのギャラリー表示機能(LuminousGallery)がありますが、ギャラリー表示ではなく、複数の画像をそれぞれ単体表示するには、querySelectorAll() などを使って複数の a 要素(trigger element)をまとめて取得し、それぞれの要素に対して new Luminous() で初期化します。
以下の例では a 要素に luminous2 というクラスを指定しています。
<div class="col-md-4"> <a class="luminous2" href="../img/01-w1800.jpg"> <img src="../img/01-w600.jpg" alt="" width="300" height="185"> </a> </div> <div class="col-md-4"> <a class="luminous2" href="../img/02-w1800.jpg"> <img src="../img/02-w600.jpg" alt="" width="300" height="185"> </a> </div> <div class="col-md-4"> <a class="luminous2" href="../img/03-w1800.jpg"> <img src="../img/03-w600.jpg" alt="" width="300" height="185"> </a> </div>
以下では querySelectorAll() で luminous2 クラスを指定した全ての a 要素を取得し、取得した要素の数が 0 より大きければ、NodeList のメソッド forEach() を使ってそれぞれの要素に対して new Luminous() で初期化しています。
//querySelectorAll() で全ての luminous2 クラスを指定した a 要素を取得 const luminousElems = document.querySelectorAll('.luminous2'); //取得した要素の数が 0 より大きければ if( luminousElems.length > 0 ) { luminousElems.forEach( (elem) => { new Luminous(elem); }); }
ギャラリー表示(LuminousGallery)
LuminousGallery を使うと、拡大表示した際に前後の画像へのナビゲーションを表示して、複数の画像にライトボックスを適用することができます。
以下の例では a 要素(trigger element)に luminous3 というクラスを指定しています。
<div class="col-md-4"> <a class="luminous3" href="../img/01-w1800.jpg"> <img src="../img/01-w600.jpg" alt="" width="300" height="185"> </a> </div> <div class="col-md-4"> <a class="luminous3" href="../img/02-w1800.jpg"> <img src="../img/02-w600.jpg" alt="" width="300" height="185"> </a> </div> <div class="col-md-4"> <a class="luminous3" href="../img/03-w1800.jpg"> <img src="../img/03-w600.jpg" alt="" width="300" height="185"> </a> </div>
JavaScript では取得した要素の集まり(NodeList や HTMLCollection)を new LuminousGallery() に渡して初期化します。
//querySelectorAll() で全ての luminous3 クラスを指定した a 要素を取得 const luminousGalleryElems = document.querySelectorAll('.luminous3'); // または getElementsByClassName() を使ってもほぼ同じ(※) //const luminousGalleryElems = document.getElementsByClassName('luminous3'); //取得した要素の数が 0 より大きければ if( luminousGalleryElems.length > 0 ) { // LuminousGallery で初期化 new LuminousGallery(luminousGalleryElems); }
※ querySelectorAll() と getElementsByClassName()
document.querySelectorAll('.luminous3') と document.getElementsByClassName('luminous3') で取得される要素はいずれも luminous3 クラスが指定されている要素ですが、querySelectorAll() で取得されるのは静的な NodeList ですが、getElementsByClassName() で取得されるのは HTMLCollection で document が変更された時点で自動的に更新されるライブオブジェクトです。
そのため、フィルタリングなどでドキュメントを操作した場合、getElementsByClassName() で取得した HTMLCollection にはその変更が反映されますが、querySelectorAll() で取得した NodeList には反映されません。
単体&ギャラリー表示
単体表示とギャラリー表示で別々のクラスを設定して、それぞれについて初期化して使用することもできますが、場合によってはページにライトボックス表示する画像が1つの場合は単体表示で、複数ある場合はギャラリー表示にすることもできます。
以下は、 .luminous を指定した a 要素を querySelectorAll() で全て取得し、取得した要素が複数ある場合は LuminousGallery を使いギャラリー表示を適用し、1つだけの場合は Luminous を使って単体表示を適用する例です。
querySelectorAll() の戻り値は NodeList なので 1つだけの場合は new Luminous() の引数には luminousElems[0] のように先頭の DOM 要素を渡します。
//ページに .luminous が複数ある場合は、ギャラリー表示、1つだけの場合は単体表示する場合の例 const luminousElems = document.querySelectorAll('.luminous'); if( luminousElems !== null ) { if( luminousElems.length > 1 ) { //対象の要素が複数ある場合は LuminousGallery でギャラリー表示 new LuminousGallery(luminousElems); }else if(luminousElems[0]){ //対象の要素が1つだけの場合 Luminous で単体表示 new Luminous(luminousElems[0]); } }
複数のギャラリー表示
1つのページ内で複数のグループに分けてギャラリー表示する例です。
以下の場合、.luminousX1、.luminousX2、.luminousX3、.luminousX4、.luminousX5、という5つの異なるクラスを指定することで、それぞれでグループごとにギャラリー表示することができます。
for(let i=1; i<6; i++) { const luminousClass = '.luminousX' + i; let luminousGalleries = document.querySelectorAll(luminousClass); if( luminousGalleries.length > 0 ) { new LuminousGallery(luminousGalleries); } }
以下はキャプション(次項)を設定する場合の例です。オプションは内容が同じでも個々に設定します。
for(let i=1; i<6; i++) { //キャプション(オプション) let luminousOptsX = 'luminousOptsX' + i; luminousOptsX = { caption: (trigger) => { if(trigger.querySelector('img').hasAttribute('alt')) { return trigger.querySelector('img').getAttribute('alt'); }else{ return ''; } }, } const luminousClass = '.luminousX' + i; let luminousGalleries = document.querySelectorAll(luminousClass); if( luminousGalleries.length > 0 ) { //LuminousGallery の場合は、第3引数にオプションを指定 new LuminousGallery(luminousGalleries, {}, luminousOptsX); } }
画像のプリロード(先読み込み)
多数の画像があり、拡大表示する画像のサイズが大きい場合などでは大きな画像の読み込みに時間がかかる場合があります。
そのような場合、拡大表示する画像をプリロード(先読み込み)しておくと、画像がメモリ上にキャッシュされ、拡大画像の表示がスムーズになります。
JavaScript で画像をプリロードするには、img 要素を生成して、src 属性に画像のパスを指定します(生成した画像は読み込まれるだけで表示されません)。
以下は、img 要素にサムネイル画像を指定して、luminous クラスを指定した a 要素の href 属性に拡大表示する画像のパスを指定してライトボックス表示する例です。
<div class="grid-wrapper"> <div class="grid"> <div class="grid-item"> <div class="grid-content"> <a class="luminous" href="images/01.jpg"> <img class="thumb" src="images/thumbs/01.jpg" alt="sample image 01"> </a> <h3 class="title">Title 1</h3> <div class="desc"> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p> </div> </div> </div> <div class="grid-item"> <div class="grid-content"> <a class="luminous" href="images/02.jpg"> <img class="thumb" src="images/thumbs/02.jpg" alt="sample image 02"> </a> <h3 class="title">Title 2</h3> <div class="desc"> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p> </div> </div> </div> <div class="grid-item"> <div class="grid-content"> <a class="luminous" href="images/03.jpg"> <img class="thumb" src="images/thumbs/03.jpg" alt="sample image 03"> </a> <h3 class="title">Title 3</h3> <div class="desc"> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p> </div> </div> </div> <div class="grid-item"> <div class="grid-content"> <a class="luminous" href="images/04.jpg"> <img class="thumb" src="images/thumbs/04.jpg" alt="sample image 04"> </a> <h3 class="title">Title 4</h3> <div class="desc"> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p> </div> </div> </div> </div> </div> <script src="luminous.min.js"></script>
以下が JavaScript で17〜22行目がプリロードの部分です。
拡大表示する画像をプリロードするには、luminous クラスを指定した a 要素の数だけ img 要素を生成して、a 要素の href 属性を img 要素の src 属性に指定します。
この例の場合、luminous クラスを指定した a 要素は、Luminous Lightbox の初期化(10行目)ですでに取得しているので、for 文で個々のリンク要素から href 属性の値を取得して、生成した img 要素の src 属性に指定しています。
<script> //img 要素の alt 属性の値をキャプションとして表示するためのオプション const luminousOpts = { caption: (trigger) => { return trigger.querySelector('img').getAttribute('alt'); }, } //全ての luminous クラスを指定した a 要素を取得 const luminousGalleryElems = document.querySelectorAll('.luminous'); //取得した要素が1つ以上あれば Luminous Lightbox を初期化 if( luminousGalleryElems.length > 0 ) { new LuminousGallery(luminousGalleryElems, {}, luminousOpts); } //画像の先読み //拡大画像へのリンク要素は上記の luminousGalleryElems で取得されているのでそれを利用 for(let i=0; i<luminousGalleryElems.length; i++) { // img 要素を生成 const img = document.createElement('img'); // img 要素の src 属性にリンクの href 属性の値を設定 img.src = luminousGalleryElems[i].href; } </script>
この例の場合、画像は4枚だけなので、プリロードしなくてもあまり変わりませんが、サイズの大きい画像が多数ある場合はプリロードしないとライトボックス表示する際に時間がかかる可能性があります。
ブラウザのインスペクタのネットワークで確認すると、拡大表示する画像がプリロードされているのが確認できます。
場合によっては load イベントでサムネイル画像を含む読み込みのすべてが完了してからプリロードする方が良いかもしれません。
window.addEventListener('load', () =>{ for(let i=0; i<luminousGalleryElems.length; i++) { const img = document.createElement('img'); img.src = luminousGalleryElems[i].href; } });
また、img 要素が読み込まれた時点で行う処理があれば以下ように画像の load イベントで実行可能です(window の load イベントと合わせて使うこともできます)。
for(let i=0; i<luminousGalleryElems.length; i++) { const img = document.createElement('img'); img.src = luminousGalleryElems[i].href; // img 要素が読み込まれた時点で行う処理があれば以下ように画像の load イベントで実行可能 img.addEventListener('load', function(){ //画像の height 及び width プロパティの値をコンソールに出力 console.log(`height:${img.height} / width:${img.width}`); }); }
この例では CSS Grid を使っています。
.grid-wrapper { padding: 1.5em; max-width: 1200px; margin-right: auto; margin-left: auto; } .grid { display: grid; grid-gap: 1rem; gap: 1rem; grid-template-columns: repeat( auto-fill, minmax( 240px, 1fr ) ); } .grid-item { background-color: #efefef; } .thumb { max-width: 100%; } .title { font-size: 16px; color: #999; text-align: center; } .desc { padding: 0 1rem; position: relative; overflow: visible; color: #aaa; font-size: 14px; }
前後の画像のみをプリロード(個人的なメモ)
前述の例では拡大(ライトボックス)表示する全ての画像をプリロードしましたが、以下はライトボックス表示した前後の画像のみをプリロードする例です(HTML と CSS は前述の例と同じ)。但し、ライトボックス表示した際に前後の画像をプリロードするので、最初にクリックしてライトボックス表示する画像はプリロードされていません。
また、ライトボックス表示される際のクラス名などを使用しているので、プラグイン自体の HTML(クラス名)などの変更があると機能しなくなります。
※ この方法が有効かどうかなどは検証できていません(個人的なメモのようなものです)。
ライトボックス表示される画像や前後の矢印ボタンはライトボックス表示されてからでないと取得できないのでオプションの onOpen: にライトボックス画像を表示する際に呼び出される関数を指定しています。
//img 要素の alt 属性の値をキャプションとして表示するためのオプション const luminousOpts = { caption: (trigger) => { return trigger.querySelector('img').getAttribute('alt'); }, onOpen: () => { //ライトボックス画像を表示する際に呼び出される関数 loadPrevNext(); }, onClose: () => { //ライトボックス画像を閉じる際に呼び出される関数(不要?) removeEvents(); } } //全ての luminous クラスを指定した a 要素を取得 const luminousGalleryElems = document.querySelectorAll('.luminous'); //取得した要素が1つ以上あれば Luminous Lightbox を初期化 if( luminousGalleryElems.length > 0 ) { new LuminousGallery(luminousGalleryElems, {}, luminousOpts); } //全ての luminous クラスを指定した a 要素の配列を作成 const luminousGalleryElems_array = Array.prototype.slice.call( luminousGalleryElems ) ; //上記配列の長さ const elems_array_length = luminousGalleryElems.length; //拡大表示する画像の src を格納する配列 const src_array = []; //luminous クラスを指定した a 要素を for 文でループ for(let i=0; i<elems_array_length; i++) { //それぞれにクリックイベントを設定 luminousGalleryElems[i].addEventListener('click', () => { //その要素が全体の何番目か(インデックス)を取得 const index = luminousGalleryElems_array.indexOf( luminousGalleryElems[i]) ; //img 要素を生成 const nextImg = document.createElement('img'); //生成した img 要素にその要素の次の要素のパスを設定してプリロード if(index === elems_array_length-1){ nextImg.src = luminousGalleryElems[0].href; }else{ nextImg.src = luminousGalleryElems[i+1].href; } //生成した img 要素にその要素の前の要素のパスを設定してプリロード const prevImg = document.createElement('img'); if(index === 0){ prevImg.src = luminousGalleryElems[elems_array_length-1].href; }else{ prevImg.src = luminousGalleryElems[i-1].href; } }); //拡大表示する画像の src を格納する配列にその要素のパスを追加 src_array.push(luminousGalleryElems[i].href); } //現在表示されている拡大画像の前の画像をプリロードする関数 const loadPrev = () => { //ライトボックス表示された画像を取得 const lumImage = document.querySelector('.lum-img'); //現在表示されている拡大画像が全体の何番目か(インデックス)を取得 const src_index = src_array.indexOf( lumImage.src) ; //img 要素を生成 const prevImg = document.createElement('img'); //生成した img 要素に現在表示されている拡大画像の前の要素のパスを設定してプリロード if(src_index === 0){ prevImg.src = src_array[src_array.length-1]; }else{ prevImg.src = src_array[src_index-1]; } } //現在表示されている拡大画像の次の画像をプリロードする関数 const loadNext = () => { //ライトボックス表示された画像を取得 const lumImage = document.querySelector('.lum-img'); //現在表示されている拡大画像が全体の何番目か(インデックス)を取得 const src_index = src_array.indexOf( lumImage.src) ; //img 要素を生成 const nextImg = document.createElement('img'); //生成した img 要素に現在表示されている拡大画像の次の要素のパスを設定してプリロード if(src_index === src_array.length-1){ nextImg.src = src_array[0]; }else{ nextImg.src = src_array[src_index+1]; } } //ライトボックス画像を表示する際に呼び出される関数を定義 const loadPrevNext = () => { //「前へ」のボタン要素 const prevButton = document.getElementsByClassName('lum-previous-button')[0]; //「次へ」のボタン要素 const nextButton = document.getElementsByClassName('lum-next-button')[0]; if(prevButton) { //「前へ」のボタン要素にクリックイベントを設定 prevButton.addEventListener('click',loadPrev); } if(nextButton) { //「次へ」のボタン要素にクリックイベントを設定 nextButton.addEventListener('click',loadNext); } } //ライトボックス画像を閉じる際に呼び出される関数を定義 const removeEvents = () => { //「前へ」のボタン要素 const prevButton = document.getElementsByClassName('lum-previous-button')[0]; //「次へ」のボタン要素 const nextButton = document.getElementsByClassName('lum-next-button')[0]; if(prevButton) { //「前へ」のボタン要素のクリックイベントを削除 prevButton.removeEventListener('click',loadPrev); } if(nextButton) { //「次へ」のボタン要素のクリックイベントを削除 nextButton.removeEventListener('click',loadNext); } }
options
以下は、Luminous に用意されているオプションと単体表示とギャラリー表示でのオプションの設定例です。ギャラリー表示(LuminousGallery)の場合は、第2引数はギャラリーオプションを指定し、第3引数にオプションを指定します。
ギャラリー表示(LuminousGallery)の場合、第2引数のギャラリーオプションを指定する必要がない場合は、空のオブジェクトを指定します。
また、オプションは生成する Luminous または LuminousGallery のインスタンスにそれぞれ作成して設定します(内容が同じだからと言って、共用すると期待通りの動作にならないようです)。
//デフォルトのオプション var options = { namespace: null, sourceAttribute: "href", caption: null, //キャプション openTrigger: "click", closeTrigger: "click", closeWithEscape: true, closeOnScroll: false, showCloseButton: true, //ドキュメントでは false となっている appendToNode: document.body, appendToSelector: null, onOpen: null, onClose: null, includeImgixJSClass: false, injectBaseStyles: true }; //単体表示の場合(第2引数にオプションを指定) new Luminous(document.querySelector(".luminous"), options); //ギャラリー表示の場合(第3引数にオプションを指定) new LuminousGallery(document.querySelector(".luminous"), {}, options);
オプション | 意味 | デフォルト値 |
---|---|---|
namespace | ライトボックス表示する際に生成される要素に付与されるクラス名のプレフィックス。例えば、'wdl' を指定すると外側の div 要素には wdl-lightbox や wdl-open クラスが追加されます。デフォルトのクラス(lum-lightbox や lum-open など)は常に付与されます。独自クラスの追加 | null |
sourceAttribute | ライトボックス画像(拡大画像)のパスを指定する属性 | "href" |
caption | キャプションに表示する文字列や文字列を返す関数。キャプションへの出力はエスケープされないのでユーザーの入力値を使用する場合は注意が必要です。 | null |
openTrigger | ライトボックス画像を表示する際のイベント | "click" |
closeTrigger | ライトボックス画像を閉じる際のイベント | "click" |
closeWithEscape | esc キーを押すことでクローズさせるかどうか | true |
closeOnScroll | スクロールでクローズさせるかどうか | false |
showCloseButton | クローズ(閉じる)ボタンを表示するかどうか | true |
appendToNode | ライトボックス画像を追加(append)するノード | document.body |
appendToSelector | ライトボックス画像を追加(append)する要素(セレクタ)。appendToNode よりも優先されます。 | null |
onOpen | ライトボックス画像を表示する際に呼び出される関数 | null |
onClose | ライトボックス画像を閉じる際に呼び出される関数 | null |
includeImgixJSClass | true を指定すると、ライトボックス内の img 要素に imgix-fluid と言うクラスを追加します。 | false |
injectBaseStyles | 基本スタイルを追加するかどうか。追加されるスタイルは injectBaseStylesheet.js により挿入されます。 | true |
ソースコード
CSS スタイル
必要に応じて独自のスタイルシートで Luminous のスタイルを上書きします。
Luminous のスタイルは luminous-basic.css に記述されているので、それを元にスタイルを設定します。
以下はライトボックス画像が表示される際に </body> の直前に挿入される HTML の例です。
<div class="lum-lightbox lum-open"> <div class="lum-lightbox-inner"> <div class="lum-lightbox-loader"></div> <div class="lum-lightbox-image-wrapper" style="width: 1603px; max-width: 1603px; height: 411px; max-height: 411px;"> <span class="lum-lightbox-position-helper"> <img class="lum-img" src="..img/01-w1800.jpg"> <p class="lum-lightbox-caption">白い蓮の花</p> </span> </div> <button class="lum-previous-button lum-gallery-button">previous</button> <button class="lum-next-button lum-gallery-button">next</button> </div> <div class="lum-close-button"></div> </div>
luminous-basic.css には例えば以下のような記述があります。
.lum-lightbox { /* ライトボックスの背景色 */ background: rgba(0, 0, 0, 0.6); } /* ライトボックス画像の表示領域 */ .lum-lightbox-inner { top: 2.5%; right: 2.5%; bottom: 2.5%; left: 2.5%; } .lum-lightbox-inner img { position: relative; } /* キャプション(画面幅が460px以上の場合) */ .lum-lightbox-inner .lum-lightbox-caption { margin: 0 auto; color: #fff; max-width: 700px; text-align: center; }
以下は独自のスタイルシートで、背景色を上書きし、z-index を追加する例です。
.lum-lightbox { background: rgba(0, 0, 0, 0.7); /* 背景色を上書き */ z-index: 9999; /* z-index を追加 */ }
以下はクローズボタンのスタイルです。X 印は :before と :after で幅2px、高さ32px、背景色が白の疑似要素をそれぞれ45度回転させて作成されています。
.lum-close-button { position: absolute; right: 5px; /* ボタンの位置 */ top: 5px; /* ボタンの位置 */ width: 32px; /* ボタンの幅 */ height: 32px; /* ボタンの高さ */ opacity: 0.3; } .lum-close-button:hover { opacity: 1; } .lum-close-button:before, .lum-close-button:after { position: absolute; left: 15px; content: " "; height: 33px; /* X 印の高さ(長さ)*/ width: 2px; /* X 印の幅(太さ)*/ background-color: #fff; } .lum-close-button:before { transform: rotate(45deg); } .lum-close-button:after { transform: rotate(-45deg); }
以下はギャラリー表示の際に表示される前後の画像への矢印ボタンのスタイルです。
.lum-previous-button { left: 12px; } .lum-next-button { right: 12px; } /* 左右の矢印ボタンの共通のスタイル */ .lum-gallery-button:after { content: ""; display: block; position: absolute; top: 50%; width: 36px; height: 36px; border-top: 4px solid rgba(255, 255, 255, 0.8); } .lum-previous-button:after { transform: translateY(-50%) rotate(-45deg); border-left: 4px solid rgba(255, 255, 255, 0.8); box-shadow: -2px 0 rgba(0, 0, 0, 0.2); left: 12%; border-radius: 3px 0 0 0; } .lum-next-button:after { transform: translateY(-50%) rotate(45deg); border-right: 4px solid rgba(255, 255, 255, 0.8); box-shadow: 2px 0 rgba(0, 0, 0, 0.2); right: 12%; border-radius: 0 3px 0 0; }
メディアクエリ
メディアクエリは 460px 以下のものが1つだけ設定されているので必要に応じて追加します。以下は luminous-basic.css に記述されている画面幅が460px以下でのスタイルです。
img の max-width と max-height が none に設定され、画像のサイズそのままが表示されるようになっていて、大きな画像の場合はユーザーはスクロールして見ることができるようになっています。
@media (max-width: 460px) { .lum-lightbox-image-wrapper { display: flex; overflow: auto; -webkit-overflow-scrolling: touch; } .lum-lightbox-caption { width: 100%; position: absolute; bottom: 0; } .lum-lightbox-position-helper { margin: auto; } /* 画像のサイズそのままが表示される */ .lum-lightbox-inner img { max-width: none; max-height: none; } }
以下は画面幅が460px以下でも画像が画面サイズ内に収まるように表示する例です(値は適当です)。
@media (max-width: 460px) { .lum-lightbox-inner img { max-width: 100vw; max-height: 95vh; } }
以下はこのページの設定例です。
画面幅が460px以下の場合、画像の横幅は最大で画面幅の2.4倍、高さは最大 90vh、キャプションは position: relative にして、クローズボタンの存在がわかりやすいように背景色や opacity を変更しています。
@media (max-width: 460px) { .lum-lightbox-inner img { max-width: 240vw; max-height: 90vh; } .lum-lightbox-caption { position: relative; } .lum-close-button { opacity: 0.7; background: rgba(0,0,0,.8); border-radius: 50%; } }
独自クラスの追加
全てのライトボックス表示のスタイルの変更は前述のように既存のスタイルを上書きすればよいのですが、複数のライトボックスのクラスを設定している場合で、特定のライトボックスに異なるスタイルを適用するにはオプションの namespace を設定して、独自のクラスを追加し、そのクラスに対してスタイルを設定することができます。
以下はオプションの namespace に 'blue' を設定する例です。
const luminousOpts5 = { //オプションの namespace に 'blue' を設定 namespace: 'blue', //キャプション caption: (trigger) => { return trigger.querySelector('img').getAttribute('alt'); }, } //luminous8 クラスを指定した要素を取得 const luminousGalleryElems3 = document.querySelectorAll('.luminous8'); //取得した要素が1つ以上あればギャラリー表示のライトボックスを生成 if( luminousGalleryElems3.length > 0 ) { //上記オプションを指定して初期化 new LuminousGallery(luminousGalleryElems3, {}, luminousOpts5); }
ライトボックス表示する画像を囲んだ a 要素に luminous8 クラスを指定
<div class="col-md-4"> <a class="luminous8" href="../img/01-w1800.jpg"> <img src="../img/01-w600.jpg" alt="白い蓮の花" width="300" height="185"> </a> </div> <div class="col-md-4"> <a class="luminous8" href="../img/02-w1800.jpg"> <img src="../img/02-w600.jpg" alt="庭に来る半野良の猫" width="300" height="185"> </a> </div> <div class="col-md-4"> <a class="luminous8" href="../img/03-w1800.jpg"> <img src="../img/03-w600.jpg" alt="枝垂れ桜と経堂" width="300" height="185"> </a> </div>
ライトボックス表示された画像には、namespace に設定した 'blue' を含むクラス(blue-lightbox や blue-lightbox-inner など)が追加されます。
全ての既存のクラス名の「lum」の部分を namespace に設定した文字列に置き換えたクラスが追加されます(既存のクラスはそのまま残ります)。
<div class="lum-lightbox blue-lightbox lum-open blue-open"> <div class="lum-lightbox-inner blue-lightbox-inner"> <div class="lum-lightbox-loader blue-lightbox-loader"></div> <div class="lum-lightbox-image-wrapper blue-lightbox-image-wrapper" style="width: 357px; max-width: 357px; height: 752px; max-height: 752px;"> <span class="lum-lightbox-position-helper blue-lightbox-position-helper"> <img class="lum-img blue-img" src="..img/01-w1800.jpg"> <p class="lum-lightbox-caption blue-lightbox-caption">白い蓮の花</p> </span> </div> <button class="lum-previous-button blue-previous-button lum-gallery-button blue-gallery-button">previous</button> <button class="lum-next-button blue-next-button lum-gallery-button blue-gallery-button">next</button> </div> <div class="lum-close-button blue-close-button"></div> </div>
例えば、以下のように追加されたクラスを使って、そのライトボックスのみにスタイルを適用することができます。
.blue-lightbox { background: rgba(51,68,166,0.6); /* 背景色を変更 */ }
アイコンを表示
画像にマウスオーバーすると SVG 画像のアイコンを表示する例です。
以下が HTML です。アイコンは span 要素で表示します。
<div class="sample-content"> <a class="luminous9" href="../img/02-w1800.jpg"> <img class="thumb" src="../img/02-w600.jpg" alt="庭に来る半野良の猫"> </a> <span class="icon-plus"></span> </div>
アイコンは span 要素に ::after 疑似要素を使って表示します。初期状態では opacity:0 で非表示にしておいてホバー時に表示するようにし、絶対配置で水平及び垂直方向に中央配置するようにしています。
関連項目:CSS で svg 要素を表示
.sample-content { position: relative; overflow: hidden; max-width: 280px; } .thumb { max-width: 100%; transition: transform 0.3s; } /*画像ホバー時に画像を拡大*/ .thumb:hover { transform: scale(1.1); } /*ホバー時に画像の上に表示するアイコン*/ .icon-plus { opacity: 0; position: absolute; /*アイコンホバー時に反応しないように*/ pointer-events: none; /* トランジションで opacity を使って表示 */ transition: opacity 0.3s; /* 以下は水平及び垂直方向に中央配置するための設定 */ top: 50%; left: 50%; margin-right: -50%; transform: translate(-50%, -50%); } /*SVG アイコンを擬似要素 ::after で表示*/ .icon-plus::after{ display: inline-block; margin: 0; content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' fill='white' class='bi bi-plus-circle' viewBox='0 0 16 16'%3E %3Cpath d='M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z'/%3E %3Cpath d='M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z'/%3E%3C/svg%3E"); } /*ホバー時にアイコンを表示*/ .sample-content:hover .icon-plus { opacity: 1; }
//オプションの設定 const luminousOpts9 = { caption: (trigger) => { //alt 属性の値をキャプションに表示 return trigger.querySelector('img').getAttribute('alt'); }, } //luminous クラスを指定した a 要素を取得 const luminousElem9 = document.querySelector('.luminous9'); //上記で要素が取得できていれば Luminous を初期化 if( luminousElem9 !== null ) { new Luminous(luminousElem9, luminousOpts9); }
以下はホバー時にキャプションも表示する例です。
キャプションは caption クラスの div 要素内の p 要素に記述しています。
<div class="grid"> <div class="grid-item"> <div class="grid-content"> <a class="luminous10" href="../img/01-w1800.jpg"> <img class="thumb" src="../img/01-w600.jpg" alt="白い蓮の花"> </a> <span class="icon-plus"></span> <div class="caption"> <p>白い蓮の花</p> </div> </div> </div> <div class="grid-item"> <div class="grid-content"> <a class="luminous10" href="../img/02-w1800.jpg"> <img class="thumb" src="../img/02-w600.jpg" alt="庭に来る半野良の猫"> </a> <span class="icon-plus"></span> <div class="caption"> <div class="caption"> <p>庭に来る半野良の猫</p> </div> </div> </div> </div> <div class="grid-item"> <div class="grid-content"> <a class="luminous10" href="../img/03-w1800.jpg"> <img class="thumb" src="../img/03-w600.jpg" alt="枝垂れ桜と経堂"> </a> <span class="icon-plus"></span> <div class="caption"> <div class="caption"> <p>枝垂れ桜と経堂</p> </div> </div> </div> </div> </div>
この例では CSS Grid を使って画像やキャプションを配置しています。
caption クラスの div 要素は初期状態では、transform: translateY(3rem) で下の方に配置して非表示にし(親要素に overflow: hidden を指定)、ホバー時に translateY(0px) で通常の位置に戻しています。
.grid { display: grid; grid-gap: 1rem; gap: 1rem; grid-template-columns: repeat( auto-fill, minmax( 240px, 1fr ) ); } .grid-item { } .grid-content { /*.caption の基準となるように position: relative を指定 */ position: relative; /*キャプションが隠れるように*/ overflow: hidden; } .thumb { max-width: 100%; transition: transform 0.3s; } /*画像ホバー時に画像を拡大*/ .thumb:hover { transform: scale(1.1); } .caption { position: absolute; /*絶対配置*/ bottom: 0; /*基準をボトムに配置*/ text-align: center; width: 100%; height: 3rem; background-color: rgba(0,0,0,0.55); transform: translateY(3rem); /*3rem 下方向に配置*/ transition: transform 0.3s; /*アニメーション表示*/ font-size: .875rem; pointer-events: none; } .caption p { color: #fff; margin-top: 1rem; } /*グリッドアイテムホバー時にキャプションを表示*/ .grid-item:hover .caption { transform: translateY(0px); } /*ホバー時に画像の上に表示するアイコン*/ .icon-plus { opacity: 0; position: absolute; transition: opacity 0.3s; top: 50%; left: 50%; margin-right: -50%; transform: translate(-50%, -50%); pointer-events: none; } .grid-item:hover .icon-plus { opacity: 1; } .icon-plus::after{ display: inline-block; margin: 0; content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' fill='white' class='bi bi-plus-circle' viewBox='0 0 16 16'%3E %3Cpath d='M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z'/%3E %3Cpath d='M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z'/%3E%3C/svg%3E"); }
// caption のオプション(img 要素の alt 属性の値をキャプションに表示) const luminousOpts10 = { caption: (trigger) => { return trigger.querySelector('img').getAttribute('alt'); }, } //全ての luminous10 クラスを指定した a 要素を取得 const luminousGalleryElems10 = document.querySelectorAll('.luminous10'); //取得した要素が存在していれば if( luminousGalleryElems10.length > 0 ) { //キャプションのオプションを指定して LuminousGallery で初期化 new LuminousGallery(luminousGalleryElems10, {}, luminousOpts10); }
関連ページ:CSS3 アニメーション SVG アイコンを表示
アイコンをクリックして表示
以下はホバー時に表示されるアイコンをクリックしてライトボックス表示する例です。
HTML では画像ではなくアイコンの要素を任意のクラス名(この例では luminous9x)を指定した a 要素で囲み、a 要素の href 属性に拡大画像のパスを指定します。
<div class="sample-content2"> <img class="thumb" src="../img/01-w600.jpg" alt="白い蓮の花"> <a class="luminous9x" href="../img/01-w1800.jpg"> <span class="icon-plus"></span> </a> </div>
この例では画像ホバー時に画像を暗く表示するように、画像の親要素の背景色に黒を指定して、画像ホバー時に画像を半透明(14行目)にしています。
前述の例ではアイコンに pointer-events: none を指定してアイコンホバー時に反応しないようにしていましたが、この例ではクリックできるように pointer-events は省略するか auto を指定します。
また、スマホなどでタッチしやすいようにアイコンには padding でタッチする範囲を広げています。
.sample-content2 { position: relative; overflow: hidden; max-width: 280px; /*画像ホバー時に暗くするように暗い背景色を指定*/ background-color: #000; } .thumb2 { max-width: 100%; transition: opacity 0.3s; } /*画像ホバー時に画像を半透明にして暗くする*/ .thumb2:hover { opacity: 0.7; } /*ホバー時に画像の上に表示するアイコン*/ .icon-plus2 { opacity: 0; position: absolute; transition: opacity .5s; top: 50%; left: 50%; margin-right: -50%; transform: translate(-50%, -50%); /*以下はデフォルトなので省略可能*/ pointer-events: auto; } .sample-content2:hover .icon-plus2 { opacity: 1; } .icon-plus2::after { display: inline-block; margin: 0; /*タッチしやすいようにタッチする範囲を広げる*/ padding: 20px; content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' fill='white' class='bi bi-plus-circle' viewBox='0 0 16 16'%3E %3Cpath d='M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z'/%3E %3Cpath d='M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z'/%3E%3C/svg%3E"); }
Luminous の初期化は通常の初期化同様、拡大画像の href 属性と任意のクラス名(この例では luminous9x)を指定した a 要素を指定します。
キャプションの指定では、trigger は a 要素なのでその親要素を parentElement で取得してそこから getElementsByTagName() で img 要素を取得しています。
const luminousOpts9x = { caption: (trigger) => { //画像要素の alt 属性を指定 return trigger.parentElement.getElementsByTagName('img')[0].getAttribute('alt'); }, } const luminousElem9x = document.querySelector('.luminous9x'); if( luminousElem9x !== null ) { new Luminous(luminousElem9x, luminousOpts9x); }
WordPress で表示
以下は WordPress で Luminous を使ってライトボックス表示する例です。
この例ではテーマのディレクトリ内に「luminous」というディレクトリを作成し、その中にLuminous 関連のファイルを配置しています。
wp-content └── themes ├── index.php └── my-theme //使用するテーマのディレクトリ ├── content.php ├── footer.php ├── functions.php ├── header.php ├── index.php ├── luminous //Luminous 関連のファイルを格納するフォルダ │ ├── luminous-basic.min.css //ダウンロードしたファイル │ ├── luminous.min.js //ダウンロードしたファイル │ └── myLuminous.js //初期化などを記述したファイル ├── sidebar.php ├── single.php └── style.css
以下は Luminous の初期化を記述したファイル myLuminous.js です。
ライトボックス表示用のクラスを2つ用意しています。
- .luminous:ページに対象の要素が複数ある場合は LuminousGallery でギャラリー表示し、1つだけの場合 Luminous で単体表示
- .lumi-solo:ページに対象の要素が複数ある場合でも常に単体表示
また、キャプションはどちらの場合も figcaption 要素に値が記述されていれば、その値を表示し、figcaption 要素がなければ img 要素の alt 属性の値を表示します。
※オプションの設定内容は全く同じですが、それぞれ個別に設定します。
//オプション(キャプション)の設定 const luminousOpts = { caption: (trigger) => { const figCaption = trigger.parentElement.querySelector('figcaption'); if(figCaption !== null && figCaption.textContent !== '') { return figCaption.textContent; }else{ if(trigger.querySelector('img').hasAttribute('alt')) { return trigger.querySelector('img').getAttribute('alt'); }else{ return ''; } } }, } //luminous クラス(単体&ギャラリー表示用)を指定した a 要素を取得 const luminousElems = document.querySelectorAll('.luminous'); if( luminousElems !== null ) { if( luminousElems.length > 1 ) { //対象の要素が複数ある場合は LuminousGallery でギャラリー表示 new LuminousGallery(luminousElems, {}, luminousOpts); }else if(luminousElems[0]){ //対象の要素が1つだけの場合 Luminous で単体表示 new Luminous(luminousElems[0], luminousOpts); } } //アイキャッチ画像用オプション(キャプション)の設定 const lumiSoloOpts = { caption: (trigger) => { const figCaption = trigger.parentElement.querySelector('figcaption'); if(figCaption !== null && figCaption.textContent !== '') { return figCaption.textContent; }else{ if(trigger.querySelector('img').hasAttribute('alt')) { return trigger.querySelector('img').getAttribute('alt'); }else{ return ''; } } }, } //lumi-solo クラス(アイキャッチ画像用:ページに1つのみ)を指定した a 要素を取得 const lumiSoloElem = document.querySelector('.lumi-solo'); //上記で要素が取得できていれば Luminous を初期化 if( lumiSoloElem !== null ) { new Luminous(lumiSoloElem, lumiSoloOpts); }
functions.php
functions.php ではダウンロードした Luminous の CSS と JavaScript、及び上記のファイルを読み込みます。
function add_my_styles_and_scripts() { ・・・その他の読み込み・・ //Luminous の JavaScript の読み込み wp_enqueue_script( 'luminous-js', get_theme_file_uri( '/luminous/luminous.min.js' ), array(), //依存するスクリプトはなし filemtime( get_theme_file_path( '/luminous/luminous.min.js' ) ), true //</body> 終了タグの前に配置 ); //Luminous の設定(初期化を記述したファイル)の読み込み wp_enqueue_script( 'my-luminous', get_theme_file_uri( '/luminous/myLuminous.js' ), array('luminous-js'), //依存するスクリプト(Luminous の JavaScript) filemtime( get_theme_file_path( '/luminous/myLuminous.js' ) ), true //</body> 終了タグの前に配置 ); //CSS の読み込み wp_enqueue_style( 'luminous-style', get_theme_file_uri( '/luminous/luminous-basic.min.css' ), array(), //依存するスタイルシートはなし filemtime( get_theme_file_path( '/luminous/luminous-basic.min.css' ) ) ); } add_action( 'wp_enqueue_scripts', 'add_my_styles_and_scripts' );
投稿に挿入した画像の表示
投稿に挿入した画像をライトボックス表示するには、投稿の編集画面でライトボックス表示する画像の設定でリンク先を「メディアファイル」にして「リンクCSSクラス」に myLuminous.js で設定したクラス「luminous」または「lumi-solo」を指定します。
キャプションを表示するには「Altテキスト」またはその画像のキャプションを設定します。
アイキャッチ画像の表示
アイキャッチ画像をライトボックス表示するには、テンプレートファイル(single.php など)でアイキャッチ画像を出力する際に拡大表示する画像へのリンクにクラス(以下の例では .lumi-solo)を指定します。
以下は投稿の個別ページで、挿入されたアイキャッチ画像があればライトボックスを適用する例です。
<?php if(have_posts()) : ?> <?php while(have_posts()) : the_post(); ?> ・・・中略・・・ <?php if(has_post_thumbnail()) : ?> <?php $post_thumbnail_id = get_post_thumbnail_id(); $my_thumbnail = get_post( $post_thumbnail_id ); $my_thumbnail_caption = esc_html( $my_thumbnail->post_excerpt ); //キャプション $src_info = wp_get_attachment_image_src( $post_thumbnail_id, 'large' ); $width = $src_info[ 1 ]; $height = $src_info[ 2 ]; ?> <figure> <!-- a 要素にライトボックス用のクラスを指定し、href に拡大画像の URL(パス)を指定 --> <a class="lumi-solo" href="<?php echo esc_url(get_the_post_thumbnail_url(get_the_ID(),'full')); ?>"> <img src="<?php echo esc_url(get_the_post_thumbnail_url(get_the_ID(),'large')); ?>" alt="<?php echo trim( strip_tags( get_post_meta( get_post_thumbnail_id($post->ID), '_wp_attachment_image_alt', true ) ) ) ?>" width="<?php echo $width; ?>" height="<?php echo $height; ?>"> </a> <figcaption><?php echo $my_thumbnail_caption ? $my_thumbnail_caption : '' ?></figcaption> </figure> <?php endif; ?> ・・・中略・・・ <?php endwhile; ?> <?php endif; ?>
関連ページ:アイキャッチ画像の出力
投稿に挿入した全ての画像に適用
以下は投稿に挿入された画像でリンク先を「メディアファイル」に設定している全ての画像を、記事の本文中の画像へのリンクを書き換えてライトボックス表示できるようにする例です。
リンクの書き換えは preg_replace_callback() を使っています。
この方法の場合、毎回画像にクラスを指定しなくてすむのと、すでに挿入されている画像もライトボックス表示の対象にできます。また、画像のリンク先を「メディアファイル」に設定していない画像はライトボックスは適用されません。
投稿のコンテンツを出力する the_content() の代わりに以下を記述します。
<?php $content = get_the_content(); // /wp-content/uploads(アップロードした画像)へのリンクを表すパターン $pattern = '/(<a )((class=")([^">]*)("))?([^>]*"http(s)?:[^">]*\/wp-content\/uploads\/[^">]*"[^>]*>)/u'; //preg_replace_callback() のコールバック関数 function add_luminous_class($matches) { if ($matches[2] !== '' && $matches[3] !== '') { //a 要素にクラスが指定されている場合は、そのクラスに続けてライトボックス用のクラスを追加 return $matches[1]. $matches[3] .$matches[4]. ' luminous' .$matches[5] .$matches[6]; } else { //a 要素にクラスが指定されていなければ、ライトボックス用のクラス属性を追加 return $matches[1]. ' class="luminous"' .$matches[5] .$matches[6]; } } $content = preg_replace_callback($pattern, 'add_luminous_class', $content); //the_content フィルターを適用 $content = apply_filters('the_content',$content); $content = str_replace( ']]>', ']]>', $content ); echo $content; ?>