LoginSignup
5
4

More than 3 years have passed since last update.

loading=lazyのリソース読み込みタイミングについて

Last updated at Posted at 2019-12-09

はじめに

この記事はZOZOテクノロジーズ #2 Advent Calendar 2019 9日目の記事になります。

Chrome76より実装されたloading属性と
loading=lazyが指定された場合のリソース読み込みタイミングについて紹介させていただきます。

loading属性について

<img src="image.png" loading="lazy" alt="" width="200" height="200">

サポートされている値は現在(2019/12/9時点)下記の通りです。

動作
auto ブラウザのデフォルトの遅延読み込み動作 (default)
lazy viewportから計算された距離に達するまで、リソースの読み込みを延期
eager ページ上の場所に関係なくリソースをすぐにロード

因みに、10x10より小さいインラインサイズを指定した要素は遅延されないらしい。

しきい値について

気になるのは loading=lazyを指定した場合のリソース読み込みタイミングですよね。

demoページをDevToolsで確認してみても
実際viewportHeightよりかなり下のimageまで読み込まれているのが確認できます。
スクリーンショット 2019-12-09 3.02.00.png

Chrome Engineering ManagerのAddy Osmani氏の記事によると

Chrome’s lazy-loading implementation is based not just on how near the current scroll position is, but also the connection speed. The lazy frame and image loading distance-from-viewport thresholds for different connection speeds are hardcoded

つまり遅延読み込みのしきい値は、接続速度に基づいてハードコードされているとのことなので
chromiumの該当コードを確認してみます。

スクリーンショット 2019-12-09 9.43.42.png

どうやら現在(2019/12/9時点)では下記のようにしきい値が定義されているようです。

connection speed image iframe
4G 3000 4000
3G 4000 5000
2G 6000 6000
slow 2g 8000 8000
offline 8000 8000
不明 5000 6000

つまり

つまり、4Gの場合だと
imageviewportHeightから3000px以内に
入ってきたタイミングで読み込みが開始される仕様になっています。

式で表すと下記のような感じでしょうか。

targetImageElement.getBoundingClientRect().top - window.innerHeight <= 3000

因みに

lazyImageLoadingDistanceはコマンドラインからオーバーライドできるようです。

canary --user-data-dir="$(mktemp -d)" --enable-features=LazyImageLoading --blink-settings=lazyImageLoadingDistanceThresholdPxUnknown=1,lazyImageLoadingDistanceThresholdPxOffline=1,lazyImageLoadingDistanceThresholdPxSlow2G=1,lazyImageLoadingDistanceThresholdPx2G=1,lazyImageLoadingDistanceThresholdPx3G=1,lazyImageLoadingDistanceThresholdPx4G=1 'https://mathiasbynens.be/demo/img-loading-lazy'

任意のしきい値を設定したい場合

結局、現状で任意のしきい値を設定したい場合は
IntersectionObserver等を使用して独自に実装する必要がありそうです。

<img class="lazy" src="placeholderImage.gif" data-src="originalImage.jpg" alt="">

const lazyImages = [].slice.call(document.querySelectorAll('img.lazy'))

const lazyImageObserver = new IntersectionObserver(
    (entries, observer) => {
        entries.forEach( entry => {
            if (entry.isIntersecting) {
                const lazyImage = entry.target
                lazyImage.src = lazyImage.dataset.src
                lazyImage.classList.remove('lazy')
                lazyImageObserver.unobserve(lazyImage)
            }
        })
    }, { rootMargin: '100px 0px 100px 0px' }
)

lazyImages.forEach((lazyImage) => {
    lazyImageObserver.observe(lazyImage)
})

参考

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4