ざこノート
2018-05-20 [js]

[js] Zooming 画像クリックで拡大表示する 親要素のz-indexに注意

依存性がなく軽量(約12KB)なZooming.jsを使用します。Material Design Liteを使用したサイトに適用したところ、ズームした画像が見えなかったため、z-indexを切り替えて対応しました。

環境

  • Windows 10 Pro 64bit 1709
  • Google Chrome 66.0.3359.181 64bit
  • Zooming.js 2.0.0
  • Material Design Lite 1.3.0

kingdido999/zooming
https://github.com/kingdido999/zooming

結果

公式デモです。
https://desmonding.me/zooming/

imgにclass='img-zoomable'を設定して、scriptを実行するだけです。
imgの親要素がz-index: autoでないとズームした画像が見えません。

<body>
<!-- Material Design Lite の Fixed header -->
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header"> <!-- z-index: auto -->
  <header class="mdl-layout__header"> <!-- z-index: 3 -->
  </header>
  <div class="mdl-layout__drawer"> <!-- z-index: 5 -->
  </div>
  <main class="mdl-layout__content"> <!-- z-index: 1 -->
    <div class="page-content"> <!-- z-index: auto -->
      <!-- ズームする画像のclassを設定します -->
      <figure><img src='img/xxx.png' class='img-zoomable' /></figure>
    </div>
  </main>
</div>

<script src="//cdnjs.cloudflare.com/ajax/libs/zooming/2.0.0/zooming.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
  var main = document.getElementsByTagName('main')[0];
  var mainZIndex = main.style.zIndex;
  new Zooming({
    // options...
    onBeforeOpen: function () {
      mainZIndex = main.style.zIndex;
      main.style.zIndex = "auto";
    },
    onBeforeClose: function () {
      main.style.zIndex = mainZIndex;
    }
  }).listen('.img-zoomable');
})
</script>
</body>

実装

imgの親要素は z-index: auto にする

画像クリックすると画像はz-index: 999になり、その背面に画面全体を覆う背景色がz-index: 998で表示されます。
ズームする画像の親要素は、z-index: autoでないと、画像は見えない状態になります。

  <main class="mdl-layout__content"> <!-- z-index: 1 -->
    <div class="page-content"> <!-- z-index: auto -->
      <!-- ズームする画像のclassを設定します -->
      <figure><img src='img/xxx.png' class='img-zoomable' /></figure>
    </div>
  </main>

mdl-layout__contentz-indexを画像ズームの間だけ、z-index: autoに設定することで対応します。

<script>
document.addEventListener('DOMContentLoaded', function () {
  var main = document.getElementsByTagName('main')[0];
  var mainZIndex = main.style.zIndex;
  new Zooming({
    // options...
    onBeforeOpen: function () {
      mainZIndex = main.style.zIndex;
      main.style.zIndex = "auto";
    },
    onBeforeClose: function () {
      main.style.zIndex = mainZIndex;
    }
  }).listen('.img-zoomable');
})
</script>

Zooming のオプション

Zoomingの公式ガイド
https://desmonding.me/zooming/docs/#/guide
公式オプション
https://desmonding.me/zooming/docs/#/configuration

document.addEventListener('DOMContentLoaded', function () {
  new Zooming({
    // 画像ズーム後にドラッグすると追加ズームするのを無効
    //   (スマホだと操作しにくく、ズーム画像も綺麗ではないため)
    enableGrab: false,
    // 画面全体を覆う背景の透明度を0.9
    //   (次の画面に進んだと勘違いして`戻る`をしないように、背景が少し見えるようにしておくため)
    bgOpacity: 0.9,
    // customSizeを設定すると、scaleBaseが無効になる -> どちらか選んで設定する
    // 画像をズームしたサイズが元画像と同じなるようにする
    //   (元画像が大きい場合は多少綺麗にズームされるGood、元画像が小さい場合は画像が荒くなるだけBad)
    customSize: 100%,
    // ブラウザサイズの端まで拡大させる
    //   (元画像が大きい場合に荒くなるBad、元画像が小さい場合は荒いけど画面いっぱいに拡大されるGood)
    scaleBase: 1,
    // 画像ズームが解除されるまでのどれだけスクロールするか (初期値: 40)
    //   (スマホで大きい画像をピンチアウトした時に、すぐズームが解除されないようにするため)
    scrollThreshold: 100,
  }).listen('.img-zoomable');
})

大きい画像を綺麗にズームすることを優先してcustomSize: 100%にしたかったのですが、小さい画像の場合はただ荒くなるだけで意味がないので、scaleBase: 1を設定しました。
ズームした時点で荒くなるので、新しいタブで元画像を開いた方が良いように思いました。
もしかしたら、綺麗に表示させる方法があるのかも知れません。

<img src="解像度悪い画像.jpg" data-original="解像度良い画像.jpg" />

その他のライブラリ

jQueryが必要のようです。

感謝