Best practice per il caricamento lento

Sebbene il caricamento lento di immagini e video offra vantaggi in termini di rendimento positivi e misurabili, non è un compito da considerare. Se commetti un errore, potrebbero avere conseguenze indesiderate. Pertanto, è importante tenere a mente le seguenti preoccupazioni.

Mind the fold

Potresti avere la tentazione di caricare lentamente ogni singola risorsa multimediale nella pagina con JavaScript, ma devi resistere a questa tentazione. Gli elementi che si trovano sopra la piega non devono essere caricati con il metodo lazy. Queste risorse devono essere considerate asset critici e quindi dovrebbero essere caricate normalmente.

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

Naturalmente, dove si trova il fold non è così chiaro al giorno d'oggi, quando i siti web vengono visualizzati su tanti schermi di varie dimensioni. Su un laptop, ciò che si trova above the fold potrebbe trovarsi sotto sui dispositivi mobili. Non esiste un consiglio a prova di proiettile per risolvere questo problema in modo ottimale in ogni situazione. Dovrai condurre un inventario degli asset critici della tua pagina e caricare queste immagini nel modo consueto.

Inoltre, è consigliabile non essere così rigoroso riguardo alla linea di piegatura che alla soglia per l'attivazione del caricamento lento. Per i tuoi scopi potrebbe essere più opportuno stabilire una zona buffer a una certa distanza below the fold, in modo che le immagini inizino a caricarsi molto prima che l'utente le faccia scorrere nell'area visibile. Ad esempio, l'API Intersection Observationr consente di specificare una proprietà rootMargin in un oggetto options quando crei una nuova istanza IntersectionObserver. In questo modo viene assegnato in modo efficace agli elementi un buffer, che attiva il comportamento di 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 ai valori che specificheresti per una proprietà margin CSS, significa che è così. 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) viene ampliato di 256 pixel. Ciò significa che la funzione di callback viene eseguita quando un elemento immagine si trova a meno di 256 pixel dell'area visibile e l'immagine inizia a caricarsi prima che l'utente la veda effettivamente.

Per ottenere questo stesso effetto nei browser che non supportano l'osservazione dell'intersezione, utilizza il codice di gestione degli eventi di scorrimento e regola il controllo getBoundingClientRect in modo da includere un buffer.

Variazione del layout e segnaposto

Il caricamento lento dei contenuti multimediali può causare uno spostamento nel layout se non vengono utilizzati i segnaposto. Queste modifiche possono disorientare gli utenti e attivare operazioni costose sul layout DOM, che consumano risorse di sistema e contribuiscono al jank. Come minimo, valuta l'utilizzo di un segnaposto in tinta unita con le stesse dimensioni dell'immagine target oppure tecniche quali LQIP o SQIP che suggeriscono il contenuto di un elemento multimediale prima che venga caricato.

Per i tag <img>, src deve inizialmente puntare a un segnaposto fino a quando questo attributo non viene aggiornato con l'URL immagine finale. Utilizza l'attributo poster in un elemento <video> per puntare a un'immagine segnaposto. Inoltre, utilizza gli attributi width e height nei tag <img> e <video>. Ciò garantisce che la transizione dai segnaposto alle immagini finali non modifichi le dimensioni visualizzate dell'elemento durante il caricamento dell'elemento multimediale.

Ritardi nella decodifica delle immagini

Il caricamento di immagini di grandi dimensioni in JavaScript e il loro rilascio nel DOM può collegare il thread principale e, di conseguenza, l'interfaccia utente non risponde 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 tieni presente che non è ancora disponibile ovunque e aggiunge complessità alla logica di caricamento lento. Se vuoi utilizzarla, dovrai cercarla. Di seguito è riportato un esempio di come utilizzare Image.decode() con un elemento di riserva:

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 a CodePen per vedere un codice simile a questo esempio in azione. Se la maggior parte delle immagini è piuttosto piccola, questo potrebbe non essere molto utile, ma può certamente aiutarti a ridurre il jank durante il caricamento lento di immagini di grandi dimensioni e il loro inserimento nel DOM.

Quando i contenuti non vengono caricati

A volte le risorse multimediali non vengono caricate per un motivo o per l'altro e si verificano errori. Quando può verificarsi questa situazione? Dipende, ma ecco un caso ipotetico: hai un criterio di memorizzazione nella cache HTML per un breve periodo di tempo (ad esempio cinque minuti) e l'utente visita il sito oppure ha lasciato aperta una scheda inattiva per un lungo periodo di tempo (ad esempio diverse ore) e torna per leggere i tuoi contenuti. A un certo punto del processo, si verifica una nuova implementazione. Durante questo deployment, il nome di una risorsa immagine cambia a causa del controllo delle versioni basato su hash oppure viene rimosso del tutto. Nel momento in cui l'utente esegue il caricamento lento dell'immagine, la risorsa non è disponibile e, di conseguenza, non funziona.

Sebbene si tratti di casi relativamente rari, potrebbe essere necessario avere un piano di backup in caso di esito negativo del caricamento lento. Per le immagini, la soluzione potrebbe avere il seguente aspetto:

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 fare 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 oppure puoi semplicemente visualizzare un messaggio di errore nell'area del segnaposto dell'immagine.

Potrebbero verificarsi anche altri scenari. Qualunque cosa tu faccia, non è mai una cattiva idea segnalare all'utente quando si è verificato un errore e possibilmente interpellare l'utente se qualcosa va storto.

Disponibilità di JavaScript

Non si deve dare per scontato che JavaScript sia sempre disponibile. Se hai intenzione di 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 riserva più semplice possibile prevede l'utilizzo di 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 negli elementi <noscript>. Per risolvere 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 i fogli di stile vengano richiesti tramite i tag <link> che rimuove la classe no-js dall'elemento <html> se JavaScript è attivato:

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

Infine, utilizza un codice CSS per nascondere gli elementi con una classe di codice lento quando JavaScript non è disponibile:

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

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