ドロップインで動くLightbox

描画領域を超える画像はアスペクト比を維持して縮小される(拡大はされない)

リンクが張られた画像をLightbox形式で表示するようなJavaScriptを書いていた。vwvh単位でa要素を引き伸ばして適当に前面に表示し、img要素をなんとなく拡大してから天地左右中央配置する。予めクラス指定が必要だったり、スタイルの追加が必要だったりしない、ドロップインで動作するものだ。

View Demo: Lightbox with Clean Markup

デモでそれぞれの画像をクリック(タッチ)すると、描画領域全体に画像が表示される。a要素をオーバーレイの背景に変え、img要素をうまく収まるように調整することになる。

if (this.href !== image.src) {
  image._src = image.src;
  image.src = this.href;
}

リンク先と画像のURLが違う場合は、画像がサムネイルでリンク先がフルサイズの画像とみなし、一時的に画像のリンク先を書き換えてフルサイズ画像が表示されるようにもなっている。サムネイルのURLは一時的に_srcプロパティーに保存しておき、閉じると元に戻るようにもした。

if (image._src) {
  image.src = image._src;
  delete image._src;
}

data-*属性を使ってやりたいところだが、スクリプトの規模に比べて大仰なポリフィルが必要になるので、オレオレプロパティーに保存している。setAttribute()getAttribute()data-*属性に使ったら負けだ。

this.style.backgroundColor = '#333';
this.style.cursor = 'zoom-out';
this.style.height = '100vh';
this.style.left = '0';
this.style.position = 'fixed';
this.style.top = '0';
this.style.width = '100vw';
this.style.zIndex = '1';

コンテキストに依存するので、lefttopプロパティーは0にする必要があるだろう。a要素はデフォルトでdisplay: inlineのため、position: fixedを指定するとblockに変わる、と仕様に規定がある。そのためわざわざthis.style.display = 'block'を指定しなくてもwidthプロパティー等はきちんと反映されるようになる。描画領域に合わせるのは100vw100vhで簡単な時代だ。

image.style.bottom = '0';
image.style.height = 'auto';
image.style.left = '0';
image.style.margin = 'auto';
image.style.maxHeight = '96%';
image.style.maxWidth = '96%';
image.style.position = 'absolute';
image.style.right = '0';
image.style.top = '0';
image.style.width = 'auto';

画像の天地左右中央配置はFirefoxの画像表示スタイルシートに幅制限を加えたものにした。FirefoxでCSSではなくJavaScriptでheightwidth属性を書き換えてリサイズしているのは何か意味があるんだろうか。最大幅を100%にしていないのは単に好みだ。

デモではPlaceIMGの画像でリンク先もそれの場合のみに有効になるようにしている。実際にはURLの判定を[src^="/img/"]やウェブサイトのドメイン、またはその両方で判定するようにすると良いだろう。


様々な事情があってHTMLファイルはいじることが難しいけれど、それらから固定で参照されているJavaScriptファイルだけは追記することが可能、というようなケースで必要になって考えていた。このように画像のURLなどから類推し、既存のHTML構造を利用してスタイルを当てていくのがコストが低い。

デモのページにも書いておいたが、実装依存はともかくz-indexプロパティーがコンテキストに依存するという問題がある。ライブラリー化するのは難しそうだ。とは言うもののストレートな実装なので汎用化しなくても良さそうではある。