Leniwe ładowanie filmu

Data publikacji: 16 sierpnia 2019 r.

Podobnie jak w przypadku elementów graficznych, możesz też stosować wolne wczytywanie filmów. Filmy są zwykle ładowane za pomocą elementu <video>, ale w przypadku filmów hostowanych w innych usługach, takich jak YouTube, mogą używać elementów <iframe> (w takim przypadku zapoznaj się z artykułem o elementach iframe z opóźnionym wczytywaniem).

Sposób wczytywania opóźnionego zależy od przypadku użycia, ponieważ istnieje kilka różnych rozwiązań.<video>

W przypadku filmów, które nie są odtwarzane automatycznie

Unikanie automatycznego odtwarzania filmów jest zwykle sprawdzoną metodą, ponieważ daje użytkownikowi kontrolę. W takich przypadkach określenie atrybutu preload w elemencie <video> to najlepszy sposób na uniknięcie wczytywania całego filmu:

<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>

Poprzedni przykład używa atrybutu preload z wartością none, aby uniemożliwić przeglądarkom wstępne wczytywanie żadnych danych wideo. Atrybut poster nadaje elementowi <video> obiekt zastępczy, który zajmie miejsce podczas wczytywania filmu.

W większości przeglądarek preload domyślnie ustawia się na metadata, a część filmu jest wstępnie wczytana za pomocą nagłówka Content-Range. Może to spowodować pobranie większej ilości danych niż jest to potrzebne, zwłaszcza jeśli przeglądarka nie obsługuje nagłówka Content-Range. Nawet jeśli jest to obsługiwane, przeglądarki nie mogą wiedzieć, w których bajtach są przechowywane metadane, i mogą one nie być przechowywane na początku pliku. Dlatego najlepszym sposobem na uniknięcie wczytywania filmu jest określenie none i użycie preload="none".

Funkcję tę można dodatkowo rozszerzyć, aby wstępnie wczytywać metadane, gdy użytkownik najedzie kursorem na film za pomocą atrybutu onmouseenter (lub za pomocą odpowiednich metod obsługi zdarzenia 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>

Dzięki temu nie tylko zmniejsza się opóźnienie podczas odtwarzania filmu, ale użytkownik od razu widzi jego czas trwania.

Filmy mogą kwalifikować się jako kandydaci do uwzględnienia w LCP. Obraz poster wczytuje się szybciej niż film, dlatego w przypadku kandydata na element LCP należy użyć obrazu plakatu, ale też wstępnie go załadować, podając wartość atrybutu 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>

Filmy zastępujące animowane GIF-y

Automatycznie odtwarzane filmy są najczęściej używane do krótkich animacji w formacie GIF. Animowane GIF-y są powszechnie używane, ale w pewnych aspektach, zwłaszcza pod względem rozmiaru pliku, są gorsze od swoich odpowiedników w formacie wideo. Animowane GIF-y mogą zajmować kilka megabajtów danych. Filmy o podobnej jakości wizualnej są zwykle znacznie mniejsze.

Używanie elementu <video> zamiast animowanego GIF-a nie jest tak proste jak w przypadku elementu <img>. Animowane GIF-y mają 3 cechy:

  1. są odtwarzane automatycznie po załadowaniu.
  2. Są one odtwarzane w pętli (chociaż nie zawsze).
  3. Nie mają ścieżki audio.

Aby to osiągnąć za pomocą elementu <video>, wykonaj te czynności:

<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>

Atrybuty autoplay, muted i loop są samoobjaśniające. playsinline jest wymagany, aby autoodtwarzanie działało na iOS. Teraz masz alternatywę dla GIF-ów, która działa na różnych platformach. Jak jednak zastosować leniwy sposób ładowania? Aby rozpocząć, zmodyfikuj znaczniki <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>

Dodaliśmy atrybut poster, który umożliwia określenie obiektu zastępczego, który zajmie miejsce elementu <video>, dopóki film nie zostanie załadowany z opóźnieniem. Podobnie jak w przypadku przykładów <img> z opóźnionym wczytywaniem, ukryj adres URL filmu w atrybucie data-src w każdym elemencie <source>. Następnie użyj kodu JavaScript podobnego do przykładów opóźnionego wczytywania obrazów za pomocą 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);
    });
  }
});

Podczas wczytywania opóźnionego elementu <video> musisz przejrzeć wszystkie elementy podrzędne <source> i zmienić ich atrybuty data-src na atrybuty src. Następnie musisz wywołać metodę load elementu, aby rozpocząć wczytywanie filmu. Po wywołaniu tej metody media zaczną automatycznie się odtwarzać zgodnie z atrybutem autoplay.

Dzięki tej metodzie masz rozwiązanie wideo, które emuluje zachowanie animowanego GIF-a, ale nie powoduje tak intensywnego wykorzystania danych jak animowane GIF-y. Możesz też ładować te treści z opóźnieniem.

Leniwe ładowanie bibliotek

W przypadku ładowania opóźnionego filmów możesz skorzystać z tych bibliotek:

  • vanilla-lazyloadlozad.js to bardzo lekkie opcje, które korzystają tylko z Intersection Observer. Są one bardzo wydajne, ale przed użyciem w starszych przeglądarkach trzeba je wypełnić.
  • yall.js to biblioteka, która korzysta z Intersection Observer i przechodzi na uchwyty zdarzeń. Może też wczytywać obrazy poster z filmem za pomocą atrybutu data-poster.
  • Jeśli potrzebujesz biblioteki ładowania opóźnionego dla Reacta, możesz użyć react-lazyload. Nie używa ona Intersection Observer, ale za to oferuje znajomą metodę opóźnionego wczytywania obrazów dla osób przyzwyczajonych do tworzenia aplikacji za pomocą React.

Każda z tych bibliotek ładowania opóźnionego jest dobrze udokumentowana i zawiera wiele wzorów znaczników do różnych zastosowań ładowania opóźnionego.