LoginSignup
34
38

More than 5 years have passed since last update.

Pure JavaScriptで画像の遅延ロード

Posted at

縦に長いWebページを作っているのですが、
Webサイトの初期表示までを高速化するために画像の遅延ロードを採用することに。

調べてみると、各種ライブラリを使用するケースがヒットしました。
おそらく、Qiita上でもっともよくまとめられているのはこちら:
LP高速化のために5つの画像の遅延読み込みライブラリを比較した

が、遅延ロードのために依存ライブラリ増やしたりスクリプト量膨らますのはちょっと、、、
ということで、少し調べてみたところ、
もっともシンプルな実装例がDavid Walsh氏によるこちら:

実装例

sample.html
<img data-src="image.jpg" alt="test image">
sample.css
img {
  opacity: 1;
  transition: opacity 0.3s;
}

img[data-src] {
  opacity: 0;
}
sample.js
[].forEach.call(document.querySelectorAll('img[data-src]'), function(img) {
  img.setAttribute('src', img.getAttribute('data-src'));
  img.onload = function() {
    img.removeAttribute('data-src');
  };
});

imgタグのsrcでなく、data-srcというattributeに画像のurlを指定しておいて、
動的に読み込み表示する、というものですね。うん、シンプル。

適用例

・スクロールに応じて遅延ロードを実行
・画像のロード完了までは、ローディング中の演出を表示

こういった代表的な遅延ロードに伴う実装の例を以下に添えておきます。
Gifアニメのローディングは綺麗なフレームレートを保とうと思うと10KB以上になったりするので
CSSアニメーションでの実装をおすすめします。

sample.html
<!--
image.jpgと同サイズのアルファのみの(透明な)default.pngをimg.srcにセットし
遅延ロードの実行前でもレイアウトが崩れないようにする。
本当はcssでimgのサイズをコントロールするのが理想ですが、
例えば、レスポンシブデザインのHTMLテンプレートを使っている場合などでは、
imgに透過画像を配置してしまった方が調整いらずで確実です。
ちなみにアルファのみの画像は tinypng などで圧縮すると極めて軽量(< 1KBになりえる)。
-->
<div class="parent-block">
  <img src="default.png" data-src="image.jpg" alt="test image">
  <div class="img-loading-animation"></div>
</div>
sample.css
img {
  opacity: 1;
  transition: opacity 0.3s;
}

img[data-src] {
  opacity: 0;
}

/*
cssでのloadingアニメーションを実現するクラスをLoading.IOなどから調達。
imgとローディングアニメーションを囲うdivを用意し、
その中央部にローディングが表示されるよう調整。
*/
.some-loading-animation { ... }
.parent-block {
  position: relative;
}
.parent-block .some-loading-animation {
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: 32px; /* 32pxはあくまで例。 .some-loading-animationの高さ / 2 の値をセット */
  margin-left: 32px; /* 32pxはあくまで例。 .some-loading-animationの幅 / 2 の値をセット */
  z-index: -1; /* imgが表示された際に背部にまわるように設定。 */
}
sample.js
window.addEventListener('scroll', (e) => {
  // window.innerHeightや、document.getElement(...).offsetTop等を使い、
  // 遅延ロードの実行を開始するスクロール量を決定。
  const scrollThreshold = XXX;
  if (window.pageYOffset >= scrollThreshold) {
    [].forEach.call(document.querySelectorAll('img[data-src]'), function(img) {
      img.setAttribute('src', img.getAttribute('data-src'));
      img.onload = function() {
        img.removeAttribute('data-src');
      };
    });
  }
});

参考

34
38
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
38