Caricamento lento del video

Pubblicato il 16 agosto 2019

Come per gli elementi immagine, ti consigliamo di utilizzare il caricamento differito anche per i video. I video vengono generalmente caricati con l'elemento <video>, anche se per i video ospitati su altri servizi come YouTube potrebbero essere utilizzati gli elementi <iframe> (in questo caso, consulta l'articolo sugli iframe con caricamento lento).

Il modo in cui eseguire il caricamento differito <video> dipende dal caso d'uso, poiché esistono diverse soluzioni.

Per i video che non vengono riprodotti automaticamente

Di solito, è buona norma evitare la riproduzione automatica dei video, poiché lascia il controllo all'utente. In questi casi, specificare l'attributo preload nell'elemento <video> è il modo migliore per evitare di caricare l'intero 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>

L'esempio precedente utilizza un attributo preload con un valore none per impedire ai browser di precaricare qualsiasi dato video. L'attributo poster assegna all'elemento <video> un segnaposto che occuperà lo spazio durante il caricamento del video.

Nella maggior parte dei browser, preload è impostato su metadata e una parte del video viene precaricata utilizzando l'intestazione Content-Range. Ciò può comportare il download di più dati del previsto, in particolare se l'intestazione Content-Range non è supportata dal browser. Anche se questa opzione è supportata, i browser non possono sapere in quali byte sono memorizzati i metadati e questi potrebbero non essere memorizzati all'inizio del file. Pertanto, le probabilità migliori di evitare il caricamento del video sono specificare none e utilizzare preload="none".

Questa funzionalità può essere ulteriormente migliorata per precaricare i metadati quando l'utente passa il mouse sopra il video con un attributo onmouseenter (o con il gestore eventi mouseenter equivalente):

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

In questo modo, non solo si riduce il ritardo quando l'utente riproduce il video, ma viene mostrata anche la durata del video non appena viene aperto.

I video possono essere considerati candidati per i LCP. Un'immagine poster viene caricata più velocemente di un video, quindi, se si tratta di un elemento LCP candidato, devi utilizzare un'immagine poster, ma anche precaricarla con un valore dell'attributo fetchpriority pari a "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>

Per i video che fungono da sostituti delle GIF animate

I video con riproduzione automatica vengono utilizzati più comunemente per animazioni rapide in stile GIF. Sebbene le GIF animate siano molto utilizzate, sono inferiori ai video in diversi modi, in particolare per le dimensioni dei file. Le GIF animate possono occupare fino a diversi megabyte di dati. I video di qualità visiva simile tendono ad essere molto più piccoli.

L'utilizzo dell'elemento <video> come sostituto della GIF animata non è così semplice come l'elemento <img>. Le GIF animate hanno tre caratteristiche:

  1. Vengono riprodotti automaticamente al caricamento.
  2. Vengono riprodotti in loop continuo (anche se non è sempre così).
  3. Non hanno una traccia audio.

Per ottenere questo risultato con l'elemento <video>, il codice sarà simile al seguente:

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

Gli attributi autoplay, muted e loop sono autoesplicativi. playsinline è necessario per la riproduzione automatica su iOS. Ora hai a disposizione una valida alternativa al video come GIF che funziona su tutte le piattaforme. Ma come si fa a eseguire il caricamento lento? Per iniziare, modifica il markup <video> di conseguenza:

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

Noterai l'aggiunta dell'attributo poster, che ti consente di specificare un segnaposto per occupare lo spazio dell'elemento <video> fino al caricamento differito del video. Come per gli esempi di caricamento differito <img>, inserisci l'URL del video nell'attributo data-src di ogni elemento <source>. Da qui, utilizza un codice JavaScript simile agli esempi di caricamento lento delle immagini basati su 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);
    });
  }
});

Quando esegui il caricamento lazy di un elemento <video>, devi eseguire l'iterazione di tutti gli elementi secondari <source> e impostare i relativi attributi data-src su attributi src. A questo punto, devi attivare il caricamento del video chiamando il metodo load dell'elemento, dopodiché i contenuti multimediali inizieranno a essere riprodotti automaticamente in base all'attributo autoplay.

Con questo metodo, hai una soluzione video che emula il comportamento delle GIF animate, ma non comporta lo stesso utilizzo intensivo dei dati delle GIF animate e puoi eseguire il caricamento lento dei contenuti.

Librerie con caricamento lento

Le seguenti librerie possono aiutarti a eseguire il caricamento differito dei video:

  • vanilla-lazyload e lozad.js sono opzioni molto leggere che utilizzano solo Intersection Observer. Di conseguenza, hanno un rendimento elevato, ma devono essere sottoposti a polyfilling prima di poter essere utilizzati su browser meno recenti.
  • yall.js è una libreria che utilizza Intersection Observer e passa ai gestori degli eventi. Può anche eseguire il caricamento differito delle immagini poster video utilizzando un attributo data-poster.
  • Se hai bisogno di una libreria di caricamento differito specifica per React, ti consigliamo di utilizzare react-lazyload. Sebbene non utilizzi Intersection Observer, fornisce un metodo familiare di caricamento lento delle immagini per chi è abituato a sviluppare applicazioni con React.

Ognuna di queste librerie di caricamento lento è ben documentata e offre molti pattern di markup per i vari tentativi di caricamento lento.