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

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

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

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

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

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

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

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

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

שימוש ב-Intersection Observer

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

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

קל יותר להשתמש ב-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 כדי לקבוע מתי רכיב נמצא בתוך אזור התצוגה, ולאחר מכן להחיל מחלקה על הרכיב הזה החלת עיצוב שמפעיל תמונת רקע. זה יגרום להורדה של התמונה בזמן הצורך ולא בטעינה הראשונית. לדוגמה, ניקח רכיב שמכיל תמונת רקע גדולה של Hero:

<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 שנוספה לרכיב כשהוא נמצא באזור התצוגה:

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