画像の遅延読み込みで表示高速化!loading=”lazy”とdecoding=”async”

画像の遅延読み込みは、Webページのパフォーマンスを向上させるために重要なテクニックの一つです。

ほとんどのWebページには複数の画像が含まれており、一つ一つの画像は比較的大きいファイルサイズを占めています。それらを一度に読み込もうとするとページの読み込み時間が遅くなってしまうため、遅延読み込み(lazy load)というテクニックが使用されます。

「画像の遅延読み込み」は、Webサイトの表示速度を高速化する上で、最優先で取り組みたい改善の一つです。
Webサイト制作やフロントエンドで必須知識ともいえる内容なので、今まで特に意識せずにimgタグを使用していた方は、是非この記事を読んでください。

目次

画像の遅延読み込みとは

通常、Webページが表示される時は、ページ内で使用されている画像を一度に全て読み込んでいます。

それを、ページ表示時には初期表示される領域内(ファーストビュー)の画像だけを読み込むようにし、画面外の画像はページがスクロールされて表示が必要になるタイミングで都度読み込む実装のことを「画像の遅延読み込み」といいます。
これにより、初期に読み込むファイル容量が減るため、ページの初期表示速度を高速化することができます。

一般的にWebサイトの表示速度を計測する際は、Page Speed Insightsや、Chrome検証ツールのLighthouseを使用するかと思います。その際、「改善できる項目」に「オフスクリーン画像の遅延読み込み」の項目が記載された場合は、画像の遅延読み込みが出来ていない影響によってページの読み込み速度が低下している証拠です。オフスクリーン(ファーストビューの領域外)の画像を遅延読み込みさせる処置を行いましょう。

画像を遅延読み込みする2つの方法

画像の遅延読み込みを行うには、大きく分けて以下の2つのパターンがあります。

  • <img>タグにloading=”lazy”を付与
  • JavaScriptを使用する(ライブラリの使用を推奨)

① <img>タグにloading=”lazy”を付与

<img>タグにloading="lazy"という記述を追加するだけで、画像を遅延読み込みさせることが可能です。
例えば、以下のように記述します。

<!-- 例 -->
<img src="example.jpg" loading="lazy" alt="" width="640" height="320">

loading="lazy"は、現在は主要なブラウザのほぼ全てに対応しています。
IEなどの非対応ブラウザでloading=”lazy”を使用した場合でも、遅延読み込みがされないだけで、画像自体は正常に読み込まれます。

loading属性には以下の3つの値を指定することができます。

lazyページ表示時には読み込まず、ページがスクロールされて表示位置が近づいたタイミングで読み込む
eagerページ表示時に読み込む
autoブラウザが、ページの読み込み速度やユーザーの接続速度に基づいて、lazyかeagerのどちらかを自動的に選択する(初期値)

このloading属性は、<img>タグだけでなく<iframe>タグにも記述することができます。
<iframe>タグは外部スクリプトなどを読み込む重い処理になることが多いので、遅延読み込みを行わせるのが良いでしょう。

遅延読み込みさせる<img>や<iframe>タグには、必ずwidth属性とheight属性を指定しましょう。
widthheightが無い場合、遅延読み込みされた要素が差し込まれることでページのレイアウトがズレるCLS(Cumulative Layout Shift)という現象が発生し、ユーザーにとってストレスとなります。
widthheightを指定することで、ページ表示時に遅延読み込みされる要素のスペースをブラウザが予め確保してくれるため、CLSを防止できます。

実際に遅延読み込みされているか確認する

具体例を見ながら解説していきます。
以下のように、10枚の画像で構成された縦に長いページを作成しました(こちらのリンクから実際に確認できます)。<img>タグのloading属性は設定しておらず、まだ画像の遅延読み込みはさせていない状態です。

画像の遅延読み込みのデモサイトをスクロールしている映像

Google Chromeの検証ツールを開き、このページ内で読み込まれるファイルを確認してみます。
(検証ツールは、Macの場合option+command+I、Windowsの場合はCtrl+Shift +IもしくはF12で開けます。)

検証ツールを開いたら、タブの中から「Network」を選択します。

Chrome検証ツールでNetworkタブを開く様子

Networkタブを開いた状態でページを再読み込みすると、ページ表示時に読み込まれたファイルが、読み込まれた順に上から一覧表示されます。
この例では、”image-01.jpg”から”image-10.jpg”までの10枚の画像が読み込まれていることがわかるでしょう。

ページ表示時にページ内の画像が全て読み込まれている例

そして、もうひとつ注目したいのが、下側の赤枠で囲った部分。

「○○MB transferred」は、現在のページを表示するためにブラウザがダウンロードした総データ量、
「○○MB resources」は、現在のページを表示するために必要なすべてのリソースの合計サイズを示しています。

このページでは、合計2.1MBのデータがダウンロードされたことになります。

このページでは、初期表示時にスクリーン内に表示されるのは2枚目の画像までです。
そのため、3枚目以降の画像の<img>タグにloading="lazy"を設定しました。

ファーストビューで表示される画像を遅延読み込みしてしまうと、ページの表示速度がわずかに遅くなります。そのため、ページ初期表示時に画面内に存在する画像に対しては、通常通り読み込ませることを推奨します。

3枚目以降の画像に遅延読み込みを施した場合のページはこちらから実際に確認いただけます。
このページのNetworkタグを確認すると以下のようになります。

遅延読み込みの実装によってページ表示時の画像の読み込みが減っている例

元々は初期表示に10枚全ての画像を読み込んでいましたが、遅延読み込みの実装により、初期表示時に読み込む画像が4枚に減少しました。

遅延読み込みさせる画像は、ページスクロールによってスクリーン内に入る手前から、ある程度余裕を持って読み込みが開始されます。
そのため、このページの例では3、4枚目の画像は画面外にいるものの、表示位置が近いために読み込まれています。(どれくらい手前で読み込まれるのかは、ブラウザやデバイスの設定によって異なる場合があります)

ページ表示時のデータ転送量は元々2.1MBでしたが、853kBに減少しました。
その分、ページの初期表示が高速化されている証拠です。

Networkタブに注目すると、初期表示時に読み込まれなかった画像も、ページスクロールで表示位置が近づいてきたタイミングで読み込まれていることがわかります。

loading='lazy'を指定した画像がスクロールによって読み込まれている様子

② JavaScriptを使用する(ライブラリの使用を推奨)

ブラウザの標準機能であるloading="lazy"を使用する方法の他、JavaScriptを使用して画像を遅延読み込みする方法があります。

自前でJavaScriptを書いて遅延読み込みを実装することも可能ですが、既に公開されている優秀なライブラリが存在するので、そちらを使用することを推奨します。

この章では、数あるライブラリの中から、lazysizesというライブラリを使用した画像の遅延読み込み方法を解説いたします。

lazysizesの基本の使い方

ライブラリをダウンロード

ライブラリをダウンロードして使用可能にするためには、以下の3つの方法があります。

a. CDNを使用する

htmlのheadタグ内に以下のコードを書き込みます。(cdnjsのサイトにて、該当ファイルの横の</>マークをクリックしてコピーし、貼り付けています)

<script src="https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.3.2/lazysizes.min.js" integrity="sha512-q583ppKrCRc7N5O0n2nzUiJ+suUv7Et1JGels4bXOaMFQcamPk9HjdUknZuuFjBNs7tsMuadge5k9RzdmO+1GQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

b. ファイルを直接ダウンロード

公式ドキュメントにアクセスして、「Code」 → 「Download ZIP」をクリック

GitHubでコードをダウンロードする操作

ダウンロードしたファイルの中から、「lazysizes.min.js」というファイルを探し、自身のプロジェクトのフォルダ内に格納。
htmlのheadタグ内に、ダウンロードしたファイルを読み込む記述をする。(src内のパスは自身のフォルダ構成に応じて書き換えてください)

<script src="./lazysizes.min.js"></script>

c. npmかbowerでインストール

npm install lazysizes --save、または、bower install lazysizes --saveを実行。

使用するJavaScriptでライブラリをインポート

import "lazysizes";
img/iframeタグに遅延読み込みのための記述をする

遅延読み込みさせたい<img>、<iframe>タグに対して、以下のように設定します。

・ファイルのパスをsrcではなく、data-srcに記載
・classにlazyloadを追加

<!-- 例 -->
<img data-src="image.jpg" class="lazyload" alt="" width="640" height="320">

これにより、ページスクロールによって要素の表示位置が近づくと、lazysizesのライブラリがsrc属性の値をdata-src属性の値に書き換えることで、画像の読み込みが開始されます。

遅延読み込みが完了すると、lazyloadクラスはlazyloadedクラスに変更されます。これによって、遅延読み込み後の要素にだけ特定のスタイルを適用させるなどの応用的な使い方も可能です。

その他の機能

プレースホルダーの表示

オプションでsrc属性を記述することで、画像を読み込み中の間に表示する画像(プレースホルダー)を設定することができます。重たい画像などを読み込む際に設定すると良いでしょう。

<!-- 例 -->
<img
    src="loading.jpg"
    data-src="image.jpg"
    class="lazyload"
    alt=""
    width="640"
    height="320"
/>

レスポンシブ対応

レスポンシブでの画像表示切り替えなどでsrcset属性を使用したい場合は、data-srcset属性に記述をすることで遅延読み込みの対応が可能です。
data-sizesを使用することで、sizes属性の値を画面幅や親要素の幅に応じて自動で設定してくれます。

<!-- 例 -->
<img
    data-sizes="auto"
    data-src="image2.jpg"
    data-srcset="image1.jpg 300w, image2.jpg 600w, image3.jpg 900w"
    class="lazyload"
    alt=""
    width="640"
    height="320"
/>

背景画像の遅延読み込み

lazysizesでは<img>や<iframe>タグ以外の遅延読み込みにも対応しており、loading="lazy"では出来ない「背景画像の遅延読み込み」が可能です。

① プラグインのダウンロード

この機能を使用するには、unveilhooksというプラグインをダウンロードする必要があります。

a. CDNを利用する場合は、以下のコードをheadタグ内に記述します。

<!-- CDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.3.2/plugins/unveilhooks/ls.unveilhooks.min.js" integrity="sha512-hQ7LIAYhD17CZh6bDzdQI7NThUHmZGcAbGDfCWHO/sOEPRAdlkQFg4gTsKhWWbI1PMUvjD7JjA+5x3pH23Bnyg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

b. ファイルを直接ダウンロードした場合は、フォルダの中から”plugins/unveilhooks/ls.unveilhooks.min.js”というファイルを探し、自身のプロジェクトフォルダに格納して読み込みます。

<script src="./ls.unveilhooks.min.js"></script>

c. npmかbowerでインストールして使用している場合は、lazysizes本体のimportの下に、unveilhooksプラグインを読み込む記述をします。

import 'lazysizes';
import 'lazysizes/plugins/unveilhooks/ls.unveilhooks';

② 背景画像を表示する要素に遅延読み込みするための設定

data-bg属性に、背景画像として読み込みたい画像のパスを指定します。css側でbackground-imageの指定をする必要はありません。
スクロールで表示位置が近づいたタイミングで、background-image: url(<data-bg属性で指定したパス>)のスタイルが自動的に付与されて、背景画像を読み込みます。

<div class="lazyload" data-bg="bg-img.jpg">
	<!-- content -->
</div>

2つの方法の使い分け

ここまで紹介してきた「loading=”lazy”を使用する方法」、「lazysizes等のJavaScriptライブラリを使用する方法」にはそれぞれ以下のようなメリット・デメリットがあります。

loading=”lazy”

メリット

  • ブラウザに標準でサポートされているため、追加のライブラリが必要ない
  • <img>、<iframe>タグに記述を追加するだけで簡単に実装できる

デメリット

  • IEや古いバージョンのブラウザには対応してしない
  • ブラウザの標準機能に一任されるため、カスタマイズできない
  • <img>、<iframe>タグに対してのみ使用できる
lazysizes等のJavaScriptライブラリ

メリット

  • IEや古いバージョンのブラウザにも対応している
  • 様々なオプションがあり、読み込み方法をカスタマイズできる
  • <img>、<iframe>タグ以外も遅延読み込みできる機能がある

デメリット

  • scriptの読み込みで初期表示速度が遅くなる可能性がある
  • 実装に多少の手間がかかる

どちらの方法を使用するべきかは、プロジェクトの要件や環境によって異なります。

loading="lazy"は現在では主要なブラウザ全てに対応しているので、基本的にはloading="lazy"での実装を検討し、IEや古いバージョンのブラウザ対応が必要な場合や、遅延読み込みに機能性を求めたい場合などはJavaScriptライブラリを使用すると良いでしょう。

WordPressにおける画像の遅延読み込み

標準機能での遅延読み込み

WordPressでは、バージョン5.5から画像の遅延読み込みが標準機能となりました。

WordPressのページ編集画面にて画像を挿入した場合、出力されるhtmlファイルの該当の<img>タグには、自動的にdecoding="async"が付与されます。(decoding=”async”については次の章で解説します)

また、ページコンテンツ内の2番目以降の画像には自動でloading="lazy"が付与されます。
1番目の画像はファーストビューの外に配置されている場合であっても、loading="lazy"は自動では付与されず、decoding="async"のみが付与されます。

遅延読み込みが自動で適用される画像は、WordPressのエディターで挿入した画像に限ります。テンプレートファイル(phpファイル)に直接記述した<img>タグには自動では適用されません。

また、WordPressのエディターでカスタムHTMLなどで<img>タグを記述した場合は、width属性とheight属性が設定されている場合に限り、loading="lazy"が付与されます。

プラグインでの遅延読み込み

WordPressの標準機能に画像の遅延読み込みが実装されたことで、画像の遅延読み込みをするためのプラグインの必要性は以前よりも薄くなりました。

プラグインはあまり入れすぎると動作が重くなったり、機能がバッティングする原因となるので、特別な理由がない限りは画像の遅延読み込みプラグインは使用しなくて良いと思います。

前述したJavaScriptライブラリと同様、プラグインもプロジェクトの要件や環境によって使用するかを選択しましょう。

decoding=”async”で画像の非同期デコード

ここまでは画像の「遅延読み込み」について解説してきましたが、ここでは画像の「非同期デコード」について解説します。
<img>タグにdecoding="async"と記述することで、画像のデコードを非同期で行うことが可能です。

decoding=”async”とは

通常、ブラウザがページを表示する際、画像をデコードしている最中はページのレンダリングをブロックしてしまい、ページの初期表示が遅れる原因となります。
decoding="async"を使用することで、画像のデコードをバックグラウンドで非同期に行うことができるため、ページのレンダリングを妨げず、初期表示速度を速くすることが可能です。

<!-- 例 -->
<img src="example.jpg" decoding="async" alt="" width="640" height="320">

loading="lazy"は、ページ初期表示時に画像の読み込みはせず、表示位置に近付いたタイミングで読み込みを行います。
それに対し、decoding="async"は、ページ初期表示時の画像読み込み自体は発生するが、それらをページのレンダリングと並行して行うというものです。非同期デコードはスクリーン外に存在する画像もページ初期表示時に読み込む点に違いがあります。

decoding="async"loading="lazy"は、以下のように併用することも可能です。この場合はloading="lazy"が優先され、ページ初期表示時の画像の読み込みは行われなくなります。

<!-- 例 -->
<img src="example.jpg" decoding="async" loading="lazy" alt="" width="640" height="320">

<img>タグのdecoding属性

<img>タグのdecoding属性には、以下の3つの値を指定することができます。

async画像を非同期にデコードし、他のコンテンツのレンダリングを妨げない
sync画像を同期的にデコードする(デコード中は他のコンテンツのレンダリングをブロックする)
autoブラウザによって最適な読み込み方法が自動的に選択される(初期値)

decoding属性も、現在では主要なブラウザの全てで使用可能で、loading属性よりも比較的古いバージョンのブラウザに対応しています。

一見すると、decoding=”sync“の同期デコードは使用するメリットが無いように思うかもしれません。
しかし、ファーストビュー内の画像をdecoding=”async“で非同期デコードすると、他のコンテンツと並行して画像のデコードが行われるので、ファーストビューの描画は遅くなります。
そのため、ファーストビュー内の画像については同期的にデコードし、他のコンテンツより優先して読み込む方が、体感的な表示速度は速くなる可能性があります。

loading属性は<img>タグと<iframe>タグに設定できましたが、decoding属性は<img>タグに対してのみ設定できます。

decoding=”async”とloading=”lazy”の使い分け

私個人の使い方になりますが、ファーストビュー以降で使用される画像については基本的にloading="lazy"による遅延読み込みを優先させています。
しかし、以下のような特別な状況下においては遅延読み込みはさせず、decoding="async"による非同期デコードのみを行わせています。

decoding=”async”だけを使用する状況
  • モーダルなど非表示/表示が切り替わるエリア内で使用される画像
  • 横スクロールすることで表示される画像
  • カルーセルなどの2枚目以降の画像

ブラウザはdisplay: none;が設定された非表示のエリア内の画像も基本的に読み込みを行いますが、loading="lazy"が設定されていると、画像がスクリーン内に存在しない判定となるため、読み込みが発生しません。
この状態で非表示から表示に切り替わると、そこから画像の読み込みが開始されるので、読み込み中の一瞬だけ画像の部分が空白で表示されてしまいます。

また、loading="lazy"での遅延読み込みは、縦スクロールの場合は、スクリーン内に入る手前のある程度余裕のある距離から読み込みが開始されるのですが、横スクロールの場合はブラウザの仕様なのか、スクリーンに入った直後のタイミングでないと読み込みが発生せず、読み込んでいる間の空白が一瞬表示されてしまいます。

そのため、上記のような状況下においてはloading="lazy"の指定はせず、decoding="async"によってページのレンダリングブロックは避けつつ、事前に画像の読み込みは完了させておくようにしています。

まとめ:画像の遅延読み込みで表示速度を高速化しよう

画像の遅延読み込みについて解説を行いました。今回の内容をまとめます。

  • 画像の遅延読み込みや非同期デコードで、ページの初期表示速度を高速化できる
  • 画像の遅延読み込みを行うには、loading=”lazy”やJavaScriptライブラリを使う方法がある
  • 遅延読み込みさせる方法は、プロジェクトの要件や環境に応じて選択する
  • decoding=”async”で画像の非同期デコードができる

今回の内容はWebサイトの表示速度を高速化するために非常に重要な内容になっていますので、是非参考にして自身のWebサイトのパフォーマンス改善に役立ててください。

内容が良かったらSNSでシェアしていただけると嬉しいです!
目次