Best practice per il caricamento lento

Sebbene il caricamento lento di immagini e video presenti vantaggi positivi e misurabili, non è un'attività da prendere con leggerezza. Un errore può avere conseguenze intenzionali. Di conseguenza, è importante tenere presenti le seguenti preoccupazioni.

Mind the fold

Potresti avere la tentazione di eseguire il caricamento lento con JavaScript per ogni singola risorsa multimediale sulla pagina, ma devi resistere a questa tentazione. Qualsiasi elemento appoggiato sopra il fold non deve essere caricato tramite caricamento lento. Queste risorse devono essere considerate asset critici, quindi caricate normalmente.

Il caricamento lento ritarda il caricamento delle risorse fino a quando il DOM non diventa interattivo, quando gli script hanno terminato il caricamento e iniziano l'esecuzione. Non è un problema per le immagini below the fold, ma le risorse critiche above the fold devono essere caricate con l'elemento <img> standard in modo da essere visualizzate il prima possibile.

Ovviamente, il punto in cui si trova il fold non è così chiaro al giorno d'oggi, quando i siti web vengono visualizzati su così tanti schermi di varie dimensioni. Sui laptop, quello che si trova above the fold potrebbe trovarsi sotto sui dispositivi mobili. Non esistono consigli a prova di proiettile per affrontare questo problema in modo ottimale in ogni situazione. Dovrai effettuare un inventario delle risorse critiche della tua pagina e caricare queste immagini come di consueto.

Inoltre, è consigliabile evitare di impostare una linea di piegatura così severa come soglia per l'attivazione del caricamento lento. Per i tuoi scopi potrebbe essere più adatto stabilire una zona buffer a una certa distanza below the fold, in modo che le immagini inizino a caricarsi bene prima che l'utente le scorra nell'area visibile. Ad esempio, l'API Intersection Observer consente di specificare una proprietà rootMargin in un oggetto opzioni quando crei una nuova istanza IntersectionObserver. In questo modo, gli elementi hanno a disposizione un buffer, che attiva il caricamento lento prima che l'elemento si trovi nell'area visibile:

let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
  // lazy-loading image code goes here
}, {
  rootMargin: "0px 0px 256px 0px"
});

Se il valore di rootMargin è simile a quelli specificati per una proprietà margin CSS, il motivo è che lo è. In questo caso, il margine inferiore dell'elemento osservato (l'area visibile del browser per impostazione predefinita, ma può essere modificato in un elemento specifico utilizzando la proprietà root) è ampliato di 256 pixel. Ciò significa che la funzione di callback viene eseguita quando un elemento immagine si trova entro 256 pixel dall'area visibile e l'immagine inizia a caricarsi prima che l'utente la veda effettivamente.

Per ottenere lo stesso effetto nei browser che non supportano la funzionalità Osserva intersezione, utilizza il codice per la gestione degli eventi di scorrimento e modifica il controllo getBoundingClientRect in modo da includere un buffer.

Spostamento del layout e segnaposto

Il caricamento lento dei contenuti multimediali può causare variazioni nel layout se non vengono utilizzati i segnaposto. Queste modifiche possono disorientare gli utenti e attivare costose operazioni di layout DOM che consumano risorse di sistema e contribuiscono al jank. Come minimo, valuta la possibilità di utilizzare un segnaposto in tinta unita che occupi le stesse dimensioni dell'immagine di destinazione oppure tecniche come LQIP o SQIP che suggeriscono i contenuti di un elemento multimediale prima che venga caricato.

Per i tag <img>, src deve inizialmente puntare a un segnaposto fino a quando l'attributo non viene aggiornato con l'URL finale dell'immagine. Utilizza l'attributo poster in un elemento <video> per puntare a un'immagine segnaposto. Inoltre, utilizza gli attributi width e height in entrambi i tag <img> e <video>. In questo modo, la transizione dai segnaposto alle immagini finali non modificherà le dimensioni di rendering dell'elemento durante il caricamento dei contenuti multimediali.

Ritardi della decodifica delle immagini

Il caricamento di immagini di grandi dimensioni in JavaScript e il loro rilascio nel DOM può legare il thread principale, facendo sì che l'interfaccia utente non risponda per un breve periodo di tempo durante la decodifica. La decodifica asincrona delle immagini utilizzando il metodo decode prima di inserirle nel DOM può ridurre questo tipo di jank, ma fai attenzione: non è ancora disponibile ovunque e aggiunge complessità alla logica di caricamento lento. Se vuoi utilizzarlo, dovrai verificarlo. Di seguito mostra come potresti utilizzare Image.decode() con un fallback:

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

if ("decode" in newImage) {
  // Fancy decoding logic
  newImage.decode().then(function() {
    imageContainer.appendChild(newImage);
  });
} else {
  // Regular image load
  imageContainer.appendChild(newImage);
}

Dai un'occhiata a questo link CodePen per vedere un codice simile a questo esempio in azione. Se la maggior parte delle immagini è di dimensioni ridotte, questo potrebbe non fare molto per te, ma può certamente ridurre i jank quando il caricamento lento di immagini di grandi dimensioni e l'inserimento nel DOM.

Quando non vengono caricati contenuti

A volte le risorse multimediali non vengono caricate per un motivo o nell'altro e si verificano errori. Quando potrebbe verificarsi il problema? Dipende, ma ecco uno scenario ipotetico: hai una norma di memorizzazione nella cache HTML per un breve periodo di tempo (ad esempio, cinque minuti) e l'utente visita il sito oppure un utente ha lasciato una scheda non attiva aperta per un lungo periodo di tempo (ad esempio diverse ore) e torna per leggere i tuoi contenuti. A un certo punto del processo, viene eseguito un nuovo deployment. Durante il deployment, il nome di una risorsa immagine cambia a causa del controllo delle versioni basato su hash o viene rimosso del tutto. Nel momento in cui l'utente esegue il caricamento lento dell'immagine, la risorsa non è disponibile e quindi non riesce.

Anche se si tratta di occorrenze relativamente rare, potrebbe essere necessario avere un piano di backup se il caricamento lento non va a buon fine. Per le immagini, la soluzione potrebbe avere un aspetto simile a questo:

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

newImage.onerror = function(){
  // Decide what to do on error
};
newImage.onload = function(){
  // Load the image
};

Le azioni che decidi di intraprendere in caso di errore dipendono dall'applicazione. Ad esempio, puoi sostituire l'area del segnaposto dell'immagine con un pulsante che consenta all'utente di tentare di caricare nuovamente l'immagine o semplicemente visualizzare un messaggio di errore nell'area del segnaposto dell'immagine.

Potrebbero sorgere anche altri scenari. Qualunque cosa tu faccia, non è mai una cattiva idea segnalare all'utente quando si è verificato un errore ed eventualmente invitarlo a intraprendere un'azione in caso di problemi.

Disponibilità di JavaScript

Non si deve presumere che JavaScript sia sempre disponibile. Se intendi eseguire il caricamento lento delle immagini, valuta la possibilità di offrire il markup <noscript> che mostrerà le immagini nel caso in cui JavaScript non sia disponibile. L'esempio di fallback più semplice possibile prevede l'utilizzo degli elementi <noscript> per pubblicare immagini se JavaScript è disattivato:

Sono un&#39;immagine!

Se JavaScript è disattivato, gli utenti vedranno sia l'immagine segnaposto sia l'immagine contenuta con gli elementi <noscript>. Per aggirare questo problema, inserisci una classe no-js nel tag <html> in questo modo:

<html class="no-js">

Poi inserisci una riga di script incorporato in <head> prima che vengano richiesti fogli di stile tramite i tag <link>, in modo da rimuovere la classe no-js dall'elemento <html> se JavaScript è attivato:

<script>document.documentElement.classList.remove("no-js");</script>

Infine, utilizza alcuni CSS per nascondere elementi con una classe lazy quando JavaScript non è disponibile:

.no-js .lazy {
  display: none;
}

Ciò non impedisce il caricamento delle immagini segnaposto, ma il risultato è più desiderabile. Gli utenti con JavaScript disattivato ottengono qualcosa di più delle immagini segnaposto, meglio dei segnaposto e non contengono affatto contenuti significativi.