Chromeのloading="lazy"によるLazyloadに関して気になっていることを調べたのでメモとして。
誤訳か勘違いしている可能性があるので、読まれる方は参考程度にお願いします。
前提
- Chrome 80.0.3987.116 で調査
- Lazily load iframes and images via ‘loading’ attribute – Chrome Platform Status
[2020.4.10追記]
Firefoxでもloading="lazy"が使えるようになった模様です。ただし初期値はeagerで、widhtやheightに関する記述はない模様。
確認したことなど
- Chromeではデフォルトでlazyが設定される?
-
- Chromeのloading属性は、指定しなくてもデフォルトで”lazy”の挙動となりうる ~loading属性の落とし穴から学ぶ、機能拡張と初期値・デフォルト挙動の話~ – Qiita
- Chromeプラットフォームのステータス
” * ‘auto’ the default behavior, which is to eagerly load the resource.”とあり、デフォルトはautoと記載あり。
初期値がautoなので、ブラウザの仕様によってはlazyにもeagerにもなる可能性がある。
lazyかeagerのどちらかで固定させるには、loading属性を各値で記載しなければならない。そのためlazyでは困る要素に対して、明示的にeagerを記載することが必須になる。
ただし、後述するinterventionによる指摘を加味すると、widhtとheightを指定していない場合は、ブラウザがlazyとして扱う設定であっても遅延表示されない可能性があるかもしれない。
- 画像サイズによるlazy適用の有無
-
- Blink LazyLoad Design Doc (public) – Google ドキュメントに記載あり。
- 10pxより(以下?)小さい画像は対象外。計測用画像に配慮しているため。
For images, <img> elements that have specified inline dimensions (as width/height attributes or in inline style) smaller than 10×10 are not deferred, in order to avoid deferring tracking pixels.
- ページアクセス時のビューポート内の要素に対するIntersectionObserver
-
- Native lazy-loading for the webに記載あり。
- IntersectionObserverが起動しない可能性あり。
- 今後改善される可能性がありそうだが、それまでは初期ビューポート内の対象要素にはlazyをつけない方がいい。
- JSによる画像の縦横サイズの取得
-
- まだ読み込まれていない画像の値も一応可能な模様だが、高さが違ったり(横長の画像なのに縦と横の値が同じになる)、縦横双方が1pxとして計測されたりした
- リロードするたびに違うということではないので、img要素の何かが影響している可能性が高いが、調べても理由は判明せず
- JSによる画像のサイズ変更
-
- addEventListenerのloadでstyle.widthによる横幅設定をした場合、通常どうり反映される
- ページの高さの変化
-
- document.body.clientHeightで高さを取得して調査(対象画像は全てwidthとheight属性を記載済み)
- 遅延読み込みされる画像の、表示前と後でページの高さが変わる
- 「遅延画像表示前>遅延画像表示後」となり、遅延画像が表示される前の方がページが長い
- 計測したところ、1画像につき、本来の画像の高さと同じだけ増えている模様
- ただし、img要素がinlieのままだと、画像の下にできるディセンダー(ベースラインとディセンダーラインの間の幅)の影響を受けるので、増える値がどの状況でも同じとは限らない
- JSを使ったスライダーへの影響
-
- ページ下部にSwiper5.3.1を設置して調査(使用ライブラリが変われば結果も変わる可能性が高いのであくまで一例として)
- スライダーが潰れたり縦に伸びたりはしない
- スライダーの場所までスクロールした際、左右に移動するためのナビゲーターの位置が下にずれており、何度かナビゲーターを押すと所定の位置に戻った(前項の高さ2倍の影響か?)
- 画像の中央に配置するようにtop:50%;とtransform:tranrateY(-50%);で要素をCSSのみで配置して確認した時は問題がなかったので、JSとCSSが絡んだ場合に発生するのか?
- JSのLazyloadとの併用1(遅延表示のタイミング)
-
- Native lazy-loading for the webに記載あり。
- ブラウザが設定した遅延読み込み開始距離よりも遠いタイミングでJSが読み込もうとする場合、ブラウザの動作の方に基づいて表示される
- ブラウザが設定した遅延読み込み開始距離よりも近いタイミングでJSが読み込もうとする場合、JSの動作の方に基づいて表示される
- 使用するLazyloa用ライブラリによって動作がちがうかもしれない(次項参照のこと)
What if I’m already using a third-party library or a script to lazy-load images or iframes?
The loading attribute should not affect code that currently lazy-loads your assets in any way, but there are a few important things to consider:- If your custom lazy-loader attempts to load images or frames sooner than when Chrome loads them normally—that is, at a distance greater than the load-in distance threshold— they are still deferred and load based on normal browser behavior.
- If your custom lazy-loader uses a shorter distance to determine when to load a particular image or iframe than the browser, then the behavior would conform to your custom settings.
※誤訳の可能性あるので原文参照のこと
- JSで設置した画像への対応
-
- Blink LazyLoad Design Doc (public) – Google ドキュメントに記載あり。
- var img = new Image()などで挿入された画像は対象外。
Also, image elements created programmatically in JavaScript (e.g. “var img = new Image()”) aren’t deferred, so that they load in as-expected.
- JSのLazyloadとの併用2(非対応ブラウザに対するフォールバック)
-
<!-- Let's load this in-viewport image normally --> <img src="hero.jpg" alt="…"> <!-- Let's lazy-load the rest of these images --> <img data-src="unicorn.jpg" alt="…" loading="lazy" class="lazyload"> <img data-src="cats.jpg" alt="…" loading="lazy" class="lazyload"> <img data-src="dogs.jpg" alt="…" loading="lazy" class="lazyload"> <script> if ('loading' in HTMLImageElement.prototype) { const images = document.querySelectorAll('img[loading="lazy"]'); images.forEach(img => { img.src = img.dataset.src; }); } else { // Dynamically import the LazySizes library const script = document.createElement('script'); script.src = 'https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.1.2/lazysizes.min.js'; document.body.appendChild(script); } </script>
'loading' in HTMLImageElement.prototypeで対応ブラウザを選り分けて動作させる。
以下も参照のこと。
- 遅延表示させる距離は変更可能か
-
- Native lazy-loading for the webに記載あり。
- 変更不可。ただし今後対応されるかもしれない。
- どの程度ビューポートに近づけば表示されるのか、という固定の値はなく、いくつかの要因できまる。
- The type of resource being fetched (image or iframe)
- Whether Lite mode is enabled
on Chrome for Android - The effective connection type
- srcset属性があっても機能するか?
-
問題なく機能する。通常どうりにimg要素にloading属性を書けばよい。
- サイズを明記しないとinterventionが出る
-
[Intervention]An <img> element was lazyloaded with loading=lazy, but had no dimensions specified. Specifying dimensions improves performance.
lazyを設定した画像にサイズ指定がない場合、上記がコンソールに表示される。
「サイズを明記した方がパフォーマンスが向上する」という指摘。- reporting/EXPLAINER.md at master · w3c/reporting · GitHub
- Intervention Reports – Chrome Platform Status
Interventionの詳細は上記などでわかるはず、だが下記(上記URL1つ目のreporting/EXPLAINER.mdから引用)のように書かれており、コンソールにでていた内容とニュアンスが違うようにも思われ、遅延表示が実行されているのかやや不安になる。
An intervention occurs when a browser decides not to honor a request made by the application (eg. for security, performance or user annoyance reasons). The report properties are the same as those for deprecations, except for the absense of anticipatedRemoval.
レスポンシブなどで画像の高さが変わる場合に関しては、HTML5であれば該当画像本来の縦横解像度をwidth属性とheight属性として書いておけばよいはず。
例えばw600pxx/h200pxの画像をHTMLにimg要素で設定する場合、実際に表示される際にはw300/h100になるとしても、width="600" height="200"と記載する。
HTML4は表示された際の解像度を記載するため、この場合は最大サイズか最小サイズの値を適当に設定するしかないと思われる。このあたりはブラウザによるレンダリングの効率化の観点から考えた方が筋かもしれないが、下記ページにあるようにwidth属性の記載の有無があまりレンダリングに影響を与えない現状であれば、「Lazyloadのためにわざわざつけなければいけない」という認識にならざるをえない。かもしれない。
- width 属性(文書中への埋込リソースの横解像度) <canvas>要素以外での扱い – HTML リファレンス
「※この箇所には、制作者の私見が入ります。」の箇所を参照のこと
また、以下のようなページも発見。
This causes chrome not to lazy load at all, and the lighthouse/audit rankings are down the drain because of this.
遅延表示にならずlighthouseでも点数が落ちたとのこと。
試したところ、今(2020.3.25)Chromeで試してもDefer offscreen imagesは監査を通っていて、開発者ツールのNetworkでも遅延表示が確認できた。
しかし今後もこのままなのかは定かではなく、widhtとheightは指定した方が安全かもしれない。なお、以下のようにintrinsicsize属性(今はaspect-ratio?)を使用することを勧める記述も一応あった。
additionally to what Ernesto Stifano has mentioned previously, the current development regarding “intrinsicsize” is more or less to “Compute img/video/canvas aspect ratio from width and height HTML attributes” – compare to https://github.com/web-platform-tests/wpt/pull/18945 and https://github.com/WICG/intrinsicsize-attribute/issues/16
ローカルの静的HTMLファイルをChromeにドラッグして表示させた場合、このinterventionは表示されない模様。
- loading=”lazy”とdecoding=”async”の併記
-
decoding=”async”とloading=”lazy”は、「如何にメインスレッドの処理を妨げないか?」を違う思想で実現したものです。従って、その仕組み上、併記しても両立はしません。
現状は、併記すると、Chromeにおいては、loading=”lazy”の方が優先されます。併記は意味がない(どちらかが適用されるのか、適用順序が変わるのか)が、視点を変えればlazyが使えないブラウザに対する対応としてasyncを記述するのはありのように思える。
ただし以下のような情報もあり。
<img loading=lazy decoding=async> lazily loads & (could) decode img async. Maybe useful for hi-res images on slow devices? I'd be careful – img will be missing til decoded. The browser may have fetched & decoded it by the time user scrolls image into view without d=a. Measure 🙂
— Addy Osmani (@addyosmani) April 10, 2019
<img loading=lazy decoding=async>
は、画像の遅延読み込みとデコードの非同期化ということです。遅いデバイス上の高解像度画像にはおそらく便利でしょう。注意点としては、 imgはデコードされるまで表示されないでしょう。ブラウザは、ユーザが画像を画面にスクロールする前にそれをデコード完了できたかもしれません:)併記にメリットがあるかどうかは、状況によるということ…?
結び
調べている途中なので書くことあれば追記予定。
画像が読み込まれる前の方が高さが増しているのは意外でした。
3人がこの記事を評価
役に立ったよという方は上の「記事を評価する」ボタンをクリックしてもらえると嬉しいです。
連投防止のためにCookie使用。SNSへの投稿など他サービスとの連動は一切ありません。