טעינה מדורגת של תמונות

תמונות יכולות להופיע בדף אינטרנט כי הן מוטמעות בתוך ה-HTML כרכיבי <img> או כתמונות רקע של CSS. בפוסט הזה תלמדו איך לבצע טעינה מדורגת של שני סוגי התמונות.

תמונות בתוך השורה

האפשרויות הנפוצות ביותר לטעינה מדורגת הן תמונות שמשמשות ברכיבי <img>. בתמונות ישירות, יש לנו שלוש אפשרויות לטעינה מדורגת, ניתן להשתמש בו בשילוב כדי לקבל את התאימות הטובה ביותר בכל הדפדפנים:

שימוש בטעינה מדורגת ברמת הדפדפן

שניהם Chrome ו-Firefox תומכים בטעינה מדורגת באמצעות המאפיין loading. אפשר להוסיף את המאפיין הזה לרכיבי <img> וגם לרכיבי <iframe>. הערך lazy מורה לדפדפן לטעון את התמונה באופן מיידי אם היא נמצאת באזור התצוגה. ומאחזרים תמונות אחרות כשהמשתמש גולל לידם.

לראות את השדה loading של ה-MDN תאימות דפדפן לטבלה לקבלת פרטים על התמיכה בדפדפן. אם הדפדפן לא תומך בטעינה מדורגת, המערכת תתעלם מהמאפיין והתמונות ייטענו מיד, כרגיל.

ברוב האתרים, הוספת המאפיין הזה לתמונות בתוך השורה תשפר את הביצועים ומאפשרות למשתמשים לטעון תמונות שייתכן שהם לא גוללים אליהן. אם יש לך כמות גדולה של תמונות וברצונך לוודא שמשתמשים בדפדפנים ללא תמיכה בהיבט של הטעינה הדרגתית תצטרכו לשלב את הדברים האלה עם אחת מהשיטות שמתוארות בהמשך.

מידע נוסף זמין במאמר בנושא טעינה מדורגת ברמת הדפדפן באינטרנט.

שימוש ב-Intersection Observer

כדי לבצע טעינה מדורגת של רכיבי <img>, אנחנו משתמשים ב-JavaScript כדי לבדוק אם הם אזור התצוגה. אם כן, מאפייני src (ולפעמים srcset) שלהם מאוכלסים בכתובות URL של תוכן התמונה הרצוי.

אם כתבתם קוד טעינה מדורגת בעבר, ייתכן שהשלמתם את המשימה באמצעות גורמים מטפלים באירועים כמו scroll או resize. אומנם הגישה הזאת המתאימים ביותר לדפדפנים שונים, דפדפנים מודרניים מציעים ביצועים טובים יותר שיטה יעילה לבדוק את החשיפה של הרכיבים באמצעות ממשק API של Intersection Observer.

קל יותר להשתמש ב-Intersection Observer ולקרוא אותו מאשר קוד שמסתמך על גורמים מטפלים באירועים, כי צריך רק לרשום צופה כדי לצפות במקום לכתוב קוד זיהוי של חשיפת רכיבים מסובך. הכול שלא נותר לעשות, הוא להחליט מה לעשות כאשר רכיב גלוי. נניח שדפוס תגי העיצוב הבסיסי הבא שלכם לרכיבי <img> שנטענים בהדרגה:

<img class="lazy" src="placeholder-image.jpg" data-src="image-to-lazy-load-1x.jpg" data-srcset="image-to-lazy-load-2x.jpg 2x, image-to-lazy-load-1x.jpg 1x" alt="I'm an image!">

יש שלושה חלקים רלוונטיים בתגי העיצוב שמומלץ להתמקד בהם:

  1. המאפיין class, שאיתו בוחרים את הרכיב עם JavaScript.
  2. המאפיין src, שמפנה לתמונת placeholder שתופיע שהדף נטען לראשונה.
  3. המאפיינים data-src ו-data-srcset, שהם מאפיינים מסוג placeholder שמכיל את כתובת ה-URL של התמונה שתיטען ברגע שהרכיב נמצא באזור התצוגה.

עכשיו נראה איך להשתמש ב-Intersection Observer ב-JavaScript כדי לבצע טעינה מדורגת תמונות שמשתמשות בתבנית הסימון הזו:

document.addEventListener("DOMContentLoaded", function() {
  var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));

  if ("IntersectionObserver" in window) {
    let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          let lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          lazyImage.srcset = lazyImage.dataset.srcset;
          lazyImage.classList.remove("lazy");
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });

    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage);
    });
  } else {
    // Possibly fall back to event handlers here
  }
});

באירוע DOMContentLoaded של המסמך, הסקריפט הזה שולח שאילתה ל-DOM עבור כל רכיבי <img> עם מחלקה של lazy. אם Intersection Observer זמין, תיצור צופה חדש שמריץ קריאה חוזרת כשרכיבי img.lazy מזינים את אזור התצוגה.

Intersection Observer זמין בכל הדפדפנים המודרניים. לכן, השימוש בה כ-polyfill של loading="lazy" יבטיח שטעינה מדורגת תהיה זמינה לרוב המבקרים.

תמונות ב-CSS

תגי <img> הם הדרך הנפוצה ביותר לשימוש בתמונות בדפי אינטרנט, אבל בתמונות אפשר להפעיל גם דרך שירות ה-CSS. background-image נכס (ונכסים אחרים). טעינה מדורגת ברמת הדפדפן לא חלה על תמונות רקע של CSS, לכן כדאי לשקול שיטות אחרות אם יש לכם תמונות רקע לטעינה מדורגת.

בניגוד לרכיבי <img> שנטענים ללא קשר החשיפה שלהם, ההתנהגות של טעינת תמונות ב-CSS מגיעה עם יותר ספקולציות. כאשר האובייקט של המסמך וה-CSS דגמים ולעבד עץ מותאמות, הדפדפן בוחן איך CSS מיושם על מסמך לפני באמצעות בקשה למשאבים חיצוניים. אם הדפדפן קבע כלל CSS שקשורה למשאב חיצוני לא רלוונטית למסמך כי כרגע נבנה, הדפדפן לא מבקש אותו.

אפשר להשתמש בהתנהגות הספקולטיבית הזו כדי לדחות את הטעינה של תמונות ב-CSS באמצעות משתמשים ב-JavaScript כדי לקבוע מתי רכיב נמצא בתוך אזור התצוגה, ומחילה מחלקה על הרכיב הזה, שמחיל עיצוב תמונת רקע. כך תתבצע הורדה של התמונה בשעת הצורך במקום בטעינה הראשונית. לדוגמה, ניקח רכיב שמכיל תמונת רקע גדולה של גיבור-על:

<div class="lazy-background">
  <h1>Here's a hero heading to get your attention!</h1>
  <p>Here's hero copy to convince you to buy a thing!</p>
  <a href="/buy-a-thing">Buy a thing!</a>
</div>

הרכיב div.lazy-background בדרך כלל מכיל את הרקע של התמונה הראשית הופעלה על ידי שירות CSS מסוים. אבל בדוגמה הזו של טעינה מדורגת, אפשר לבודד המאפיין background-image של הרכיב div.lazy-background דרך visible ה-class התווסף לרכיב כשהוא נמצא באזור התצוגה:

.lazy-background {
  background-image: url("hero-placeholder.jpg"); /* Placeholder image */
}

.lazy-background.visible {
  background-image: url("hero.jpg"); /* The final image */
}

מכאן, צריך להשתמש ב-JavaScript כדי לבדוק אם הרכיב נמצא באזור התצוגה (באמצעות Intersection Observer! ), ומוסיפים את המחלקה visible באותו הזמן ברכיב div.lazy-background, שטוען את התמונה:

document.addEventListener("DOMContentLoaded", function() {
  var lazyBackgrounds = [].slice.call(document.querySelectorAll(".lazy-background"));

  if ("IntersectionObserver" in window) {
    let lazyBackgroundObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          entry.target.classList.add("visible");
          lazyBackgroundObserver.unobserve(entry.target);
        }
      });
    });

    lazyBackgrounds.forEach(function(lazyBackground) {
      lazyBackgroundObserver.observe(lazyBackground);
    });
  }
});

ההשפעות על Largest Contentful Paint (LCP)

טעינה מדורגת היא אופטימיזציה נהדרת שמפחיתה גם את השימוש הכולל בנתונים וגם את התחרות ברשת במהלך ההפעלה, על ידי דחיית הטעינה של התמונות לזמן שבו הן נחוצות בפועל. הפעולה הזו יכולה לקצר את זמן ההפעלה ולקצר את העיבוד ב-thread הראשי על ידי צמצום הזמן הדרוש לפענוח הקוד של התמונות.

עם זאת, טעינה מדורגת היא שיטה שיכולה להשפיע על ה-LCP בגרסת התוכן הכי גדול (LCP) של האתר בצורה שלילית, אם אתם נלהבים יותר מדי מהשיטה. רצוי להימנע מטעינה מדורגת של תמונות שנמצאות באזור התצוגה במהלך ההפעלה.

כשמשתמשים במטענים זמניים שמבוססים על JavaScript, מומלץ להימנע מטעינה מדורגת של תמונות בתצוגה בתוך התצוגה, כי הפתרונות האלה משתמשים בדרך כלל במאפיין data-src או data-srcset כ-placeholder במאפייני src ו-srcset. הבעיה כאן היא שהטעינה של התמונות האלה תתעכב כי סורק הטעינה מראש של הדפדפן לא יכול למצוא אותן במהלך ההפעלה.

גם שימוש בטעינה מדורגת ברמת הדפדפן לצורך טעינה מדורגת של תמונה באזור התצוגה עלול להוביל לתוצאה הפוכה. כשמחילים את loading="lazy" על תמונה באזור התצוגה, התמונה הזו מתעכבת עד שהדפדפן יידע בוודאות שהיא נמצאת באזור התצוגה, וזה יכול להשפיע על ערך ה-LCP של דף.

לעולם לא לבצע טעינה מדורגת של תמונות שמוצגות באזור התצוגה במהלך ההפעלה. זהו דפוס שישפיע על מדד ה-LCP באתר באופן שלילי, וכתוצאה מכך על חוויית המשתמש. אם דרושה לך תמונה בזמן ההפעלה, מומלץ לטעון אותה בזמן ההפעלה במהירות האפשרית, על ידי טעינה מדורגת של התמונה.

ספריות בטעינה מדורגת

כדאי להשתמש בטעינה מדורגת ברמת הדפדפן כשאפשר, אבל אם אתם מוצאים את עצמכם במצב שבו אין אפשרות לעשות זאת, כמו קבוצה משמעותית של משתמשים שעדיין מסתמכת על דפדפנים ישנים יותר, תוכלו להשתמש בספריות הבאות כדי לטעון תמונות באופן מדורג:

  • lazysizes הוא פתרון עצלני עם כל הפיצ'רים בטעינה מדורגת של תמונות ורכיבי iframe. הדפוס שבו הוא משתמש די בדומה לדוגמאות הקוד שמוצגות כאן, מכיוון שהוא מקושר באופן אוטומטי המחלקה lazyload ברכיבי <img>, ומחייבת לציין כתובות URL של תמונות מאפיינים data-src ו/או data-srcset, שהתוכן שלהם הוחלף במאפייני src ו/או srcset, בהתאמה. הוא משתמש בצומת Observer (שניתן לבצע בו-polyfill), וניתן להרחיב אותו באמצעות מספר יישומי פלאגין כדי לבצע פעולות כמו טעינה מדורגת של סרטונים. מידע נוסף על השימוש בשכבות עגולות.
  • vanilla-lazyload הוא אפשרות קלה לטעינה מדורגת של תמונות, תמונות רקע, סרטונים, iframes, וסקריפטים. הוא משתמש ב-Intersection Observer, תומך בתמונות רספונסיביות מאפשר טעינה מדורגת ברמת הדפדפן.
  • lozad.js הוא עוד מכשיר קל שמשתמשת רק ב-Intersection Observer. לכן היא בעלת ביצועים גבוהים, אבל יהיה צורך בו מילוי פוליגוני כדי להשתמש בו בדפדפנים ישנים יותר.
  • אם דרושה לכם ספרייה של טעינה מדורגת ספציפית ל-React, כדאי לשקול react-lazyload. אומנם לא משתמש ב-Intersection Observer, הוא מספק שיטה מוכרת של עצלנים וטוענים תמונות בשביל אלו שרגילים לפיתוח אפליקציות באמצעות React.