文系卒のWebエンジニアの成長と備忘録
エンジニア経験を生かして発信するメディアサイト

【脱jQuery】JavaScriptで書く画像の遅延読み込み処理『lazyload』の実装

traffic-light-trails-street

こんにちはYsです。

この記事ではpureのJavaScriptで画像の遅延読み込みの実装方法を書いていこうと思います。この機能を作る理由は3つ。

  1. サイトの速度改善
  2. 速度改善によるSEO効果UP
  3. 速度改善によるユーザービリティの向上

当サイトでは画像の遅延読み込みを実装していますが、遅延読み込みは画像を読み込むサイトを運営する上ではほぼ必須と言っても過言ではありません。

昨今では画像の質が高くなってきている事もあり、画像のファイルサイズがかなり大きいです。その所為で画像を読み込むのに時間がかかり、結果的にサイトの描写速度が下がり、SEO的にもよくありません。

上記の対策には2通りあります。
・画像ファイルを圧縮する
・遅延読み込みを実施して、画像の読み込みを遅らせる

画像圧縮はWordpressの場合はプラグインを、プラグインを使いたくないという人向けには画像圧縮サイトなどを利用して、圧縮してからアップロードするといったやり方があります。

一方、遅延読み込みは一応wordpressの場合はプラグインもありますが、結局処理が重たくなるので自前のプログラムなどを作った方が読み込みも早くて良いです。

WPを使っている人、自作サイトを作っている人向けにこのやり方について書きます。

目次

  • 遅延読み込みの仕組み
  • HTML側の修正
  • JavaScriptでプログラムを書いていく

遅延読み込みの仕組み

遅延読み込みとは、初期描写では読み込ませず、後からデータを読み込ませる技術です。(そのままですね)

一般にWebサイトを描写する時は<head>タグから上から順番にHTMLを読み込んでから、その中でPHPだったりサーバーサイドのプログラムが読み込まれます。

この時に画像などを途中で読み込んでいる場合、どうなるかというと
HTML描写と同時に画像があるサーバーにアクセスするために、描写が遅れるといった事象が発生します。

この同時に描写するのを処理を避けて、HTMLファイルの描写が終わってから画像を読み込ませる(画像にアクセスする)といった技術が遅延読み込みです。

最初はファイルサイズが小さいダミー画像を読み込ませておいて、HTMLの描写が終わり次第、ファイルサイズが大きめの実際に載せたい画像を読み込ませます。

ダミー画像を用意する

ダミー画像は一般的に読み込んでいる風のGIF画像を用意することが多いので、当記事でもそのパターンを利用します。
のようなGIF画像を使うと、「今、読み込んでまーす」とユーザーに促すことができます。

読み込んでいる風のGIFは以下からダウンロードできるので好きなのを使いましょう。出来るだけファイルサイズが小さいものを選ぶと良いです。(できれば2KB〜4KB前後)
≫ giphy

HTML側の修正

HTML側の修正をしていきます。まずはimgタグの中身を修正していきます。

imgタグにはなんらかの処理を施してあり、DBから取得した画像をそのままimgタグに挿入していると思います。そのため出力は以下ような感じですね。

<figure>
	<img class="thumbnail" src="https://hoge.com/images/hoge.png" alt="hoge">
</figure>

この状態を修正して、初期にはダミー画像を挿入し、後から本番の画像を読み込ませるように修正し、
本番の画像は一旦data属性と言われるものに格納しておき、画像自体の読み込みはさせないようにします。

最終的には以下のような出力になるように設定します。

<figure>
	<img class="thumbnail" src="https://hoge.com/images/gray.gif" data-src="https://hoge.com/images/hoge.png">
</figure>

上記だけでは、読み込んでいるのはloadのgifが表示されているだけです。
次にJavaScriptでこのdata属性のものをsrc部分に置き換える作業を書いていきます。

JavaScriptで遅延読み込みのプログラムを書いていく

説明の前に『今なぜ、jQueryなどを使用しないpureのJavasScriptでプログラムを書くのか』という疑問があると思います。その答えはただ1つ。

jQueryを使用すると描写が遅くなるから

これだけですね。速度に拘り過ぎるとキリがないのであまり気にし過ぎるとよくないのですがjQueryは当サイトではあまり速度の観点から使用したくないので使っていません。

話が少し脱線してしまいましたが
今現在、ダミー画像のload.gifが出力されているので、JavaScript側でこのGifを取り去り、data属性に格納している表示したい画像を置換します。

遅延読み込みのタイミングを考える

遅延読み込みのタイミングは、初期描写が終わった段階。
つまりサーバーサイドの処理が終わり、HTML側に全て必要な情報が出力された段階で画像の読み込みを発生させる必要があります。

JavaScriptでサイトの描写が終わったタイミングでイベントを発生させるにはloadイベントを使用します。

window.addEventListener('load', () => {
	// ここに処理を書いていく
});

これで大枠の準備ができました。

data属性で設定した画像を全て取得する

document.querySelectorAllを使用して、data属性を全て配列で取得します。以下のような感じ。

document.querySelectorAll('img[data-src]');

この配列をループで回して、data属性の中身をimgタグのsrc属性に格納します。
for文の部分にforEachを使っていない理由は通常のfor文の方が処理が早いからです。(ここはお好みで)

var images = document.querySelectorAll('img[data-src]');
for(var i = 0; i < images.length; i++) {
    images[i].setAttribute('src', images[i].getAttribute('data-src'));
}

全体像は以下になります。これを<script>タグに入れて読み込めばlazyloadの実装は完了。

window.addEventListener('load', () => {
    var images = document.querySelectorAll('img[data-src]');
    for(var i = 0; i < images.length; i++) {
        images[i].setAttribute('src', images[i].getAttribute('data-src'));
        images[i].onload = function() {
            images[i].removeAttribute('data-src');
        }
    }
});

まとめ

以前作成しているサイトで、画像の読み込みに時間がかかり描写が遅すぎる問題があったので実際にlazyloadを作成してみました。

フリー画像サイトの画像を持っていくると普通に20KBの画像とかるので、それを上部に3,4個読み込むともう初期描写はめちゃくちゃ遅れます。

それに加えてcssやjQueryなどを読み込んでいたら更に遅れ、PCの場合は良いですが、スマホで見ている方からすると描写速度の遅れはかなりストレス。

更に言えば、Twitterのタイムラインの読み込みやGoogleのアドセンス広告なども読み込みが爆遅なので対策が必要ですね。

他にも一般的に出来る速度改善は

  • HTML, CSS, 画像の圧縮
  • ブラウザ、サーバーキャッシュの利用
  • PHP側のリファクタリング

とかですがやはり自分で出来る範囲でも結構限界がありますが、少しでもストレスフリーにユーザーが使ってもらうために1つずつ改善していければと思います。

次はiframe系の遅延読み込みを試してみたいと思います。

 

\記事のシェアをお願いします!/