画像をポップアップ表示するためのウルトラライトなライトボックスを考えてみた

この記事はだいぶ前に書かれたものなので情報が古いかもしれません
えるしっているか

この記事を三行にまとめると

えるしっているか。軽量厨はjQueryを使わない
たぶんこれが一番軽いと思います(確証はない)
ブログ記事の文量を軽くしろっつー話なんですけどね
えるしっているか。死神はjQueryを使わない



画像をクリックした時にポップアップで拡大表示したいことは(まれに)よくあると思います。

この手の機能はJavaScriptのプラグインがいくつもあるので自作しなくても簡単に実装はできます。例えばjQueryを利用したLightboxとかですね。

導入自体は難しくないのでプラグインに頼るのはもちろんアリなのですが、上記のLightboxにしても他のプラグインにしてもそこそこ作り込まれているため、ファイルサイズはそれなりです。Lightboxの場合はjQueryの読み込みも必要ですしね。や、決して重いわけではないけどね。スマホで撮った画像よりはずっと軽いです。もちろんサラマンダーよりずっt

でも世の中には僕のように死神と契約して軽量厨に魂を売ってしまった中二病の人もいるかもしれないので、今回はそんな「デスノートに名前は書かれたくないけど画像をポップアップ表示するための超軽量なコードは書きたい」という方のために、余計な作り込みを一切排除した夜神ライトボックス風な機能を考えてみました。jQueryも不要なのでだいぶ軽量です。ファミコンの初代スーパーマリオブラザーズ(40KB)よりも軽量です。



まずはこいつを見てくれ

とりまサンプルページを用意したので、実際の動きを確認したい方はまずこちらのページにある画像を適当にクリックしてみてください。

ライトボックス風サンプル

とにかくコードの量を減らすことを第一に作ったので、プラグインのようなイケてるエフェクトとかは一切ありません。画像をクリックしたら拡大表示されて、拡大表示中の画面をクリックしたら元に戻る。それだけです。

こんな挙動でも良ければだいぶお手軽なコードで実装できます。



HTMLとCSS、そしてJavaScript

サンプルページのコードはこんな感じになっています。

//HTML
<img src="konjaku1.jpg" class="popup" height="200" />
<img src="konjaku2.jpg" class="popup" height="200" />
<img src="cats.jpg"  class="popup" height="200" />

<div id="modal" class="hidden">
  <div id="modal-content">
    <img id="modal-image" src="" />
  </div>
</div>

//CSS
#modal {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  z-index: 1000;
  background: rgba(0,0,0,.85);
}
#modal-content {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
}
#modal-image {
  max-width: calc(100vw - 20px);
  max-height: calc(100vh - 20px);
}
.hidden {
  display: none!important;
}

//JavaScript
$modal = document.getElementById('modal');
$img = document.getElementById('modal-image');
images = document.querySelectorAll('.popup');

for (let i = 0; i < images.length; i++) {
  images[i].onclick = function() {
    $img.src = this.src;
    $modal.classList.remove('hidden');
  }
}

$modal.onclick = function() {
  $modal.classList.add('hidden');
}

これで全部です。これだけあればライトボックス風な見せ方ができます。JavaScriptも十数行で済みます。ね、簡単でしょう?

やっていることとしては「modal」というIDを持つポップアップ用のブロック要素を用意して「display:none」で隠しておき、画像をクリックしたら非表示を解除すると同時にブロック要素の中にあるimgタグにクリックした画像をセットするという動きです。要素の表示、非表示の切り替えは直接スタイルを操作しても良いのですが、今回は「hidden」という非表示用のクラスを作成して、そいつをつけたり削除したりして表示を切り替えています。これに関しては好みのやり方で良いと思います。

サイトの構造によっては多少書き換える必要があるかもですが、元がたいしたコードじゃないのでカスタマイズは難しくないと思います。あと先ほども言いましたが一般的なライトボックスのようなエフェクトなどは一切ありません。でもエフェクトが欲しいという場合も上記のコードに何らかのアニメーションをつけ足せば良いだけなので、そこまでおおがかりな改修にはならないかなーとは思います。JavaScriptでエフェクトつけても良いし、CSSのアニメーションでもOK。



小さい画面で見る場合

上記のCSSを見ると画像のところに「max-width」や「max-height」の設定が入っています。ここからも分かる通り、今回のコードは画面サイズに合わせて画像がレスポンシブに拡大、縮小するようになっています。つまり拡大表示とは言いつつも画面を小さくすれば元の画像よりも小さく表示されてしまうこともあるかもしれません。

画面サイズに依存せずにポップアップ画像を一定の大きさを保ちたいという場合はCSSを一部書き換えればオッケーです。

#modal {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  z-index: 1000;
  background: rgba(0,0,0,.85);
  overflow: scroll;
}
#modal-content {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  padding: 10px;
}
#modal-image {
  max-width: calc(100vw - 20px);
}
.hidden {
  display: none!important;
}

書き換えたのは以下の四点です。
・#modalに「overflow: scroll」を追加
・#modal-contentに「padding: 10px」を追加
・#modal-contentの「height: 100vh」を「min-height: 100vh」に変更
・#modal-imageの「max-height」を削除

この変更によって画像の高さは画面サイズに依存しなくなり、はみ出た分はスクロールできるようになります。


基本的にはこれで問題ないのですが、この書き方には一つ欠点があります。

それはIEのこんちくしょうさんが「display: flex」を指定した要素に対して「min-height」を認識してくれないことです。上記のコードでは「align-items: center」を指定することによりポップアップ画像が画面の中央に表示されるようにしています。でもIEの場合、flex要素に「height」を指定した場合は大丈夫なのですが「min-height」で高さを指定しても高さが無視されてしまうらしく「align-items: center」が上手く効いてくれません。

個人的にはIEだけの話だし、せいぜい中央表示ができない程度だから、そっちがmin-heightを無視するならこっちもIEさんへの対応は無視してやんよくらいのスタンスで良いとは思いますが、IEでもちゃんと中央に表示したいという場合はもう少しCSSに改良を加えるか、おとなしくスクロールをあきらめるかするしかないかなと……僕はあきらめました。






てな感じで、ライトボックス風のサンプルでしたー。

あかつきのお宿ではサンプルページだけじゃなくてブログの記事全部にこのエセライトボックスを実装しています(少しカスタマイズしていますが)。対応したのはつい最近なんですけどね。ぶっちゃけライトボックス自体いらねーとか思ってたんですけど、画像をクリックすると別ページに飛んでしまうのは確かにあまり良い動きとは言えないなと思いまして、でもこのサイトは軽量化のためにjQueryともバイバイキーンな作りにしてしまったので、何かしら簡単なコードでライトボックスに近い動きを実装できないかなーと思った結果、上記のコードを書いてみるという運びになりました。たぶんこれが一番軽いと思います(確証はない)

まあ軽量厨に徹したいなら、コードを軽量化するよりも先に普段のブログ記事の文量を軽くしろっつー話なんですけどね……今回もこの程度の内容なのに4000文字近くあるからな(コードを含む)
 もしかしたら何か関連しているかも? 
 質問や感想などお気軽にコメントしてください