Help us understand the problem. What is going on with this article?

Pure JavaScriptで画像の遅延ロード

More than 1 year has passed since last update.

縦に長い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');
      };
    });
  }
});

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした