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

תאריך פרסום: 16 באוגוסט 2019

בדומה לרכיבי תמונה, כדאי גם להשתמש בטעינה איטית של סרטונים. סרטונים נטענים בדרך כלל באמצעות הרכיב <video>, אבל בסרטונים שמתארחים בשירותים אחרים כמו YouTube, יכול להיות שייעשה שימוש ברכיבים מסוג <iframe> (במקרה כזה, כדאי לעיין במאמר בנושא טעינה איטית של iframe).

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

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

<video controls preload="none" poster="one-does-not-simply-placeholder.jpg">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

בדוגמה הקודמת נעשה שימוש במאפיין preload עם ערך none כדי למנוע מדפדפנים לטעון מראש כל נתוני וידאו. המאפיין poster מעניק לרכיב <video> placeholder שיתפוס את המקום בזמן טעינת הסרטון.

ברוב הדפדפנים, הערך שמוגדר כברירת מחדל ל-preload הוא metadata, וחלק מהסרטון נטען מראש באמצעות הכותרת Content-Range. כתוצאה מכך, יכול להיות שיורדו יותר נתונים ממה שרצוי – במיוחד אם הדפדפן לא תומך בכותרת Content-Range. גם אם התכונה הזו נתמכת, הדפדפנים לא יכולים לדעת באילו ביטים המטא-נתונים מאוחסנים, ויכול להיות שהם לא מאוחסנים בתחילת הקובץ. לכן, כדי למנוע את טעינת הסרטון, הכי טוב לציין את none ולהשתמש ב-preload="none".

אפשר לשפר את הקוד הזה עוד יותר כדי לטעון מראש את המטא-נתונים כשהמשתמש מעביר את העכבר מעל הסרטון עם מאפיין onmouseenter (או עם פונקציית הטיפול באירועים mouseenter המקבילה):

<video controls
  preload="none"
  poster="one-does-not-simply-placeholder.jpg"
  onmouseenter="event.target.setAttribute('preload','metadata')">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

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

סרטונים יכולים לעמוד בדרישות של מועמדים לתוכנית LCP. טעינת תמונה מסוג poster תהיה מהירה יותר מטעינת הסרטון, לכן אם מדובר ברכיב LCP פוטנציאלי, כדאי להשתמש בתמונה סטטית, אבל גם לטעון אותה מראש עם ערך המאפיין fetchpriority של "high":

<link rel="preload" href="one-does-not-simply-placeholder.jpg" as="image" fetchpriority="high">
<video controls preload="none"
  poster="one-does-not-simply-placeholder.jpg"
  onmouseenter="event.target.setAttribute('preload','metadata')">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

לסרטון שמשמש כתחליף לקובץ GIF מונפש

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

השימוש ברכיב <video> כתחליף ל-GIF מונפש לא פשוט כמו השימוש ברכיב <img>. קובצי GIF באנימציה מתאפיינים בשלושה מאפיינים:

  1. הם מופעלים באופן אוטומטי כשהם נטענים.
  2. הם חוזרים על עצמם בלי הפסקה (אבל זה לא תמיד המצב).
  3. אין להם טראק אודיו.

כדי לעשות זאת באמצעות הרכיב <video>, צריך להשתמש בקוד הבא:

<video autoplay muted loop playsinline>
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

המאפיינים autoplay,‏ muted ו-loop הם ברורים מאליהם. playsinline נחוץ כדי שההפעלה האוטומטית תתבצע ב-iOS. עכשיו יש לכם סרטון חלופי בפורמט GIF שעובד בכל הפלטפורמות. אבל איך מבצעים טעינה מדורגת של הקוד? כדי להתחיל, משנים את ה-Markup של <video> בהתאם:

<video class="lazy" autoplay muted loop playsinline width="610" height="254" poster="one-does-not-simply.jpg">
  <source data-src="one-does-not-simply.webm" type="video/webm">
  <source data-src="one-does-not-simply.mp4" type="video/mp4">
</video>

תוכלו לראות את ההוספה של המאפיין poster, שמאפשר לציין placeholder שיתפוס את המרחב של רכיב <video> עד שהסרטון ייטען באיטרציה. בדומה לדוגמאות לטעינה איטית של <img>, שומרים את כתובת ה-URL של הסרטון במאפיין data-src בכל רכיב <source>. לאחר מכן, משתמשים בקוד JavaScript שדומה לדוגמאות לטעינה הדרגתית של תמונות שמבוססות על Intersection Observer:

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

  if ("IntersectionObserver" in window) {
    var lazyVideoObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(video) {
        if (video.isIntersecting) {
          for (var source in video.target.children) {
            var videoSource = video.target.children[source];
            if (typeof videoSource.tagName === "string" && videoSource.tagName === "SOURCE") {
              videoSource.src = videoSource.dataset.src;
            }
          }

          video.target.load();
          video.target.classList.remove("lazy");
          lazyVideoObserver.unobserve(video.target);
        }
      });
    });

    lazyVideos.forEach(function(lazyVideo) {
      lazyVideoObserver.observe(lazyVideo);
    });
  }
});

כשאתם מעמיסים באופן איטי רכיב <video>, אתם צריכים לעבור על כל רכיבי הצאצאים <source> ולהפוך את המאפיינים data-src שלהם למאפיינים src. לאחר מכן, צריך להפעיל את הטעינה של הסרטון על ידי קריאה ל-method‏ load של האלמנט. לאחר מכן, המדיה תתחיל לפעול באופן אוטומטי בהתאם למאפיין autoplay.

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

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

הספריות הבאות יכולות לעזור לכם לטעון וידאו באיטרציה:

  • vanilla-lazyload ו-lozad.js הן אפשרויות קלילות במיוחד שמשתמשות ב-Intersection Observer בלבד. לכן, הביצועים שלהם טובים מאוד, אבל צריך לבצע להם פוליפיל כדי שאפשר יהיה להשתמש בהם בדפדפנים ישנים יותר.
  • yall.js היא ספרייה שמשתמשת ב-Intersection Observer ומשתמשת בטיפולי אירועים כחלופה. אפשר גם לטעון בטעינה איטית תמונות poster של סרטונים באמצעות מאפיין data-poster.
  • אם אתם צריכים ספרייה ספציפית לטעינה איטית ב-React, כדאי לכם לנסות את react-lazyload. הספרייה לא משתמשת ב-Intersection Observer, אבל כן מספקת שיטה מוכרת של טעינת תמונות בזמן אמת (lazy loading) למפתחים רגילים לפתח אפליקציות עם React.

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