loading=”lazy” の落とし穴?画像遅延読み込みの最適化テクニック

目次

1️⃣ はじめに

loading="lazy" は画像の遅延読み込みを自動的に処理する便利な機能ですが、ブラウザの制御に依存するため、意図しない動作を引き起こすことがあります。

今回紹介する lazyload-prioritize.js は、通常の画像がすべて読み込まれた後に、loading="lazy" を適用した画像を ビューポートに近い順 に優先的に読み込むスクリプトです。


2️⃣ コードの解説

📌 スクリプトの全体像

lazyload-prioritize.js

document.addEventListener("DOMContentLoaded", () => {
    console.log("スクリプト開始: lazyload-prioritize.js");

    const lazyImages = document.querySelectorAll("img[loading='lazy']");
    const normalImages = document.querySelectorAll("img:not([loading='lazy'])");
    let normalImagesLoaded = 0;

    console.log(`通常画像の数: ${normalImages.length}`);
    console.log(`Lazy画像の数: ${lazyImages.length}`);

    function checkNormalImagesLoaded() {
        console.log(`読み込まれた通常画像数: ${normalImagesLoaded} / ${normalImages.length}`);

        if (normalImagesLoaded === normalImages.length) {
            console.log("すべての通常画像が読み込まれました!Lazy画像の優先読み込みを開始します。");
            prioritizeLazyImages();
        }
    }

    // **通常画像のロード完了をカウント**
    normalImages.forEach(img => {
        if (img.complete) {
            console.log(`すでに読み込まれている画像: ${img.src}`);
            normalImagesLoaded++;
        } else {
            img.onload = () => {
                normalImagesLoaded++;
                console.log(`読み込み完了: ${img.src}`);
                checkNormalImagesLoaded();
            };
            img.onerror = () => {
                console.warn(`読み込み失敗: ${img.src}`);
                normalImagesLoaded++; // 失敗してもカウントを進める
                checkNormalImagesLoaded();
            };
        }
    });

    // **ビューポートに近いLazy画像から優先的に読み込む**
    function prioritizeLazyImages() {
        if (lazyImages.length === 0) {
            console.log("Lazy画像がありません。処理を終了します。");
            return;
        }

        const distances = [];

        // **すべてのLazy画像のビューポートからの距離を計算**
        lazyImages.forEach(img => {
            const rect = img.getBoundingClientRect();
            const distance = Math.abs(rect.top); // ビューポートの上からの距離
            distances.push({ img, distance });
        });

        // **距離が近い順にソート**
        distances.sort((a, b) => a.distance - b.distance);

        // **距離が近い順に画像をロード**
        distances.forEach(({ img }, index) => {
            setTimeout(() => {
                console.log(`優先読み込み開始: ${img.src}`);
                img.removeAttribute("loading"); // lazy を削除
                img.src = img.src; // 強制リロード
            }, index * 100); // 100ms 間隔で順番に読み込み
        });
    }

    // **ページロード時に通常画像がすでに読み込まれているかチェック**
    checkNormalImagesLoaded();
});

📌 コードのポイント

1️⃣ 通常の画像を監視し、すべて読み込まれたら lazy 画像の処理を開始

通常の画像 (loading="lazy" が付いていないもの) の読み込みが完了するまで待機します。

  • normalImages.forEach(img => {...}) で通常の画像を監視し、すべての画像が読み込まれたら prioritizeLazyImages() を実行します。

2️⃣ loading="lazy" の画像をビューポートに近い順にロード

lazyImages.forEach(img => {...}) で各画像の ビューポートの上からの距離 (rect.top) を計算し、近い順にソート します。

  • setTimeout() を使い、100ms 間隔 で順番に画像を読み込むことで、急激なリソースの増加を防ぎます。
  • img.removeAttribute("loading") により、loading="lazy" を解除し、即時ロードを可能にします。

3️⃣ 読み込みエラー対策

画像の読み込みに失敗した場合でも onerror でカウントを進め、処理が止まらないようにしています。


3️⃣ このスクリプトのメリット

通常の画像がすべて読み込まれてから lazy 画像を優先的にロード
スクロール前に表示するべき画像が適切にロードされる
ビューポートに近い画像から優先的に読み込むため UX が向上
急激なリソースの消費を防ぎ、スムーズなページ読み込みを維持


4️⃣ まとめ

このスクリプトを導入することで、loading="lazy" の画像をより効果的に制御し、ページの表示速度を最適化できます。

loading="lazy"そのまま適用するだけでは UX や SEO に悪影響を及ぼす可能性 がありますが、本スクリプトを導入することで、

  • 通常画像の読み込みを優先し、Lazy Load の画像を適切に制御
  • ビューポートに近い画像から優先的にロードすることで UX を向上

することができます。


よかったらシェアしてね!
  • URLをコピーしました!
目次