スキップしてメイン コンテンツに移動

画像のloading-lazy:遅延読み込みによる高速化について

サイトの画像はその他のコンテンツと比べて容量が多くてサイトの表示速度を大きく下げることがある。画像の表示速度を上げることはサイトの利便性を高めることに繋がり易い。

HTMLで簡単に取り入れられてしかも効果が大きいloading-lazyの使い方を考えてみたい。

loading-lazyは画像の遅延読み込みを指定する

明るい森の木に逆さまにぶら下がるホフマンフタユビナマケモノ

loadingは画像のimg要素、さらに別枠のiframe要素にも使える属性で、画像などの読み込みの開始位置を制御できる。

loading属性で指定できる二つの値

eager
画像などを記載位置で読み込む(初期値)。
lazy
画面内の画像などをレイアウト処理後に読み込み、画面外の画像などを読み込まない。

初期値のeagerは何もしないのと同じで、従来と変わらない。ただし不要というわけではなく、loading属性がないとブラウザが勝手にlazyの動作をする場合があるのを確実に止めたりするのに使える。

lazyが画像の高速化で注目されるけど、特に「画面外のコンテンツは読み込まない」という遅延読み込みが相当に期待される。

HTMLの記載例

<img src="画像URL" alt="説明文" loading="lazy">

サイトで下の方とか直ぐに表示されない画像が多かったり、少しでも重かったりするほどにブラウザが読み込まないで最初の画面の表示速度を高める効果は大きい。

訪問者がページ全体を観るとも限らないので、無駄なデータを取らせない/通信量を必要以上に増やさせないことにも繋がる。

画面内のコンテンツの場合はブラウザがサイトの内容とデザインを把握してどのように表示するかのレイアウトを決めてから読み込みが行われるから後回しの処理になる。レイアウトを決めるまでのブラウザの処理の一連の流れを止めないから何もしないよりはページは速くなるかも知れないけれどもloading-lazyの画像などは単体で遅くなるかも知れない。指定される数や重さによって後回しの処理の影響は変わるはずだし、ページ全体の表示速度に対してどちらが速いかは一概にいえないにせよ、最初の画面で画像などを単体で全く遅延なしに最速で出したければ何もするべきではないのは確かだ。

loading-lazyは画面外からスクロールに合わせて完全に読み込みが遅延される場合も含めてコンテンツの縦幅のheight属性と横幅のwidth属性もある方が望ましいとされる。

HTMLの記載例

<src="画像URL" alt="説明文" height="縦幅" width="横幅" loading="lazy">

画像などにheight属性とwidth属性を使うだけでもブラウザのレイアウトの算出がスムーズになってサイトの表示速度を上げるといわれるけど、ただしloading-lazyにとってはそれよりも後から画像などがページに追加された際の周りのコンテンツの移動を防ぐのが目的になる。

訪問者のスイッチを押すなどのサイト上の操作を妨げる恐れがあるから予期しないコンテンツの移動は避ける方が利便性が高い。

ブラウザは画像のimgや別枠のiframeの縦横比が分からないとレイアウトのスペースが取れないらしく、CSSで指定しても上手く行かなくてHTMLのそれぞれの要素にheightとwidthの属性を使わなくてはならない。

サイトのパフォーマンスをPageSpeed Insightsで測るとCumulative Layout Shift(累積レイアウト変更)の項目に出て来る。どのくらいコンテンツが移動したかが分かる。およそloading-lazyを使って悪化したらheightとwidthを一緒に付けて改善できるかも知れない。

loading-lazyは当初はChromeブラウザの機能だったのがHTMLに標準化されて徐々に普及して来た。現時点、Lazy loading via attribute for images & iframesで確認すると人気のブラウザでもSafari(設定を変えれば対応)やOperaなどが対応してないのは注意しなくてはならない。

動作は従来のJavaScriptのIntersection Observationを使った遅延読み込みと同じなんだ。

遅延して読み込むimgとiframe要素のため、それらの段階は遅延読み込みintersection observerコールバックか遅延読み込みの属性がEagerに設定されたときに実行されます。これによって要素の読み込みが続けられることになります。

原文

For img and iframe elements that will lazy load, these steps are run from the lazy load intersection observer's callback or when their lazy loading attribute is set to the Eager state. This causes the element to continue loading.

※文中の「それらの段階」はブラウザのJavaScriptの適用とloading-lazyの動作と切り替え(読み込み開始)の三つの判定の流れのこと。

Lazy loading attributes|HTML Standard(訳文と説明は筆者)

Loading属性はトラッキング対策(ブラウザに訪問者の閲覧情報を不用意に収集させない)としてブラウザのJavaScriptがオフだと機能しないけど、とにかく未対応のブラウザにも画像などの遅延読み込みを使いたい場合は従来のIntersection ObservationなどのJavaScriptの方法だけで続けるか振り分ける必要がある。

JavaScriptの振り分けのソースコード

if ("loading" in HTMLImageElement.prototype) {
 /* loading属性に対応済みのブラウザ用の記載 */
} else {
 /* loading属性に未対応のブラウザ用の記載 */
}

JavaScriptを使う場合はloading-lazyの対象の要素のHTMLも遅延読み込みで差し替える前の状態、画像URLなどを非表示で格納する「data-」を付けた属性に予め書き換えておく必要があるから手間が増える。

サイトのデザインが変わるわけではないので、余程の高速化を得なければ未対応のブラウザがあっても支障はないといえなくもない。

imgとiframe要素以外の画像の遅延読み込みの方法

loading属性はimgとiframe要素にしか使えないので、CSSで表示する背景画像は対象外になる。画面外で遅延読み込みを行うとサイトの表示速度に有利なのは同じなので、するとJavaScriptでスクロールに合わせて画像URLを差し替える従来の方法を取り入れることになる。

CSSのbackground-imageの場合は画像URLの差し替え方がHTMLのimgやiframeの場合とは少し違う。背景画像の最初の非表示のstyleに対して予め用意しておいた画像URL、例えばstyle内の別の指定先に分けたりしたものをJavaScriptのIntersection Observerなどで差し替えることになる。

関連:画像のdecoding-async:非同期処理による高速化について

参考:decoding="async" VS loading="lazy" <img>: 画像埋め込み要素 画像の遅延読み込みにloading属性とJavaScriptを併用した最大限のパフォーマンスを発揮させる実装方法

コメント