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

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

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

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

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

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

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

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

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

שימוש במציג הצומת

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

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

קל יותר לקרוא את ה-Intersection Viewer מאשר קוד שמסתמכים על גורמים מטפלים באירועים שונים, כי צריך לרשום צופה רק כדי לצפות ברכיבים במקום לכתוב קוד מעצבן לזיהוי חשיפה של אלמנטים. כל מה שנשאר לעשות הוא להחליט מה לעשות כשהרכיב גלוי. נניח את דפוס הסימון הבסיסי הזה עבור רכיבי <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 Reportinger ב-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. אם יש לך אפשרות ליצור צופה חדש, כדאי ליצור צופה חדש שיריץ קריאה חוזרת (callback) כשרכיבי img.lazy נכנסים לאזור התצוגה.

'צפייה בצמתים' זמין בכל הדפדפנים המודרניים. לכן, שימוש בו כ-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 בדרך כלל מכיל את תמונת הרקע הראשית (Hero) שמופעלת על ידי שירות CSS מסוים. עם זאת, בדוגמה הזו של הטעינה המושהית, אפשר לבודד את המאפיין background-image של האלמנט div.lazy-background באמצעות מחלקה visible שנוספה לרכיב כשהוא באזור התצוגה:

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

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

מכאן, משתמשים ב-JavaScript כדי לבדוק אם הרכיב נמצא באזור התצוגה (עם Intersection Exploreer!), ומוסיפים את המחלקה 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, בהתאמה. הוא משתמש ב-Intersection Observer (שאפשר למלא אותו ב-polyfill), ואפשר להרחיב אותו באמצעות מספר יישומי פלאגין כדי לבצע פעולות כמו טעינה מדורגת של סרטונים. מידע נוסף על השימוש במידות עצלנות
  • vanilla-lazyload היא אפשרות פשוטה לטעינה מדורגת של תמונות, תמונות רקע, סרטונים, מסגרות iframe וסקריפטים. הוא משתמש ב-Intersection Viewer, תומך בתמונות רספונסיביות ומאפשר טעינה עצלה ברמת הדפדפן.
  • lozad.js היא אפשרות קלה נוספת שמשתמשת ב-Intersection Viewer בלבד. לכן הביצועים שלה טובים מאוד, אבל צריך למלא אותה באמצעות פוליגון כדי להשתמש בה בדפדפנים ישנים יותר.
  • אם אתם צריכים ספרייה של טעינה מדורגת ספציפית ל-React, תוכלו להשתמש ב-react-lazyload. אומנם לא נעשה שימוש ב-Intersection שפות, אבל כן מספקת שיטה מוכרת לטעינה מדורגת של תמונות, למי שרגילים לפתח אפליקציות עם React.