Ottimizza l'interazione con la prossima visualizzazione

Scopri come ottimizzare il valore Interaction to Next Paint del tuo sito web.

Interaction to Next Paint (INP) è una metrica stabile di Core Web Vital che valuta l'adattabilità complessiva di una pagina alle interazioni degli utenti osservando la latenza di tutte le interazioni idonee che si verificano durante la visita di un utente a una pagina. Il valore INP finale corrisponde all'interazione più lunga osservata (a volte ignorando i valori anomali).

Per offrire una buona esperienza utente, i siti web dovrebbero fare in modo che il valore Interaction to Next Paint sia pari o inferiore a 200 millisecondi. Per assicurarti di raggiungere questo target per la maggior parte degli utenti, una buona soglia da misurare è il 75° percentile dei caricamenti di pagine, segmentato per dispositivi mobili e computer.

I valori INP buoni sono pari o inferiori a 200 millisecondi, quelli scarsi sono superiori a 500 millisecondi e tutti i valori intermedi richiedono miglioramenti.

A seconda del sito web, le interazioni potrebbero essere poche o nulle, ad esempio pagine costituite principalmente da testo e immagini con pochi o nessun elemento interattivo. In alternativa, nel caso di siti web come editor di testo o giochi, potrebbero esserci centinaia, se non migliaia, di interazioni. In entrambi i casi, se il valore dell'INP è elevato, l'esperienza utente è a rischio.

Migliorare l'INP richiede tempo e impegno, ma il premio è un'esperienza utente migliore. In questa guida verrà esplorato un percorso per migliorare l'INP.

Scopri cosa causa un INP scadente

Prima di poter correggere le interazioni lente, devi disporre di dati che ti indichino se l'INP del tuo sito web è scarso o deve essere migliorato. Una volta ottenute queste informazioni, puoi passare al laboratorio per iniziare a diagnosticare le interazioni lente e trovare una soluzione.

Trovare interazioni lente sul campo

Idealmente, il tuo percorso di ottimizzazione dell'INP inizierà con i dati sul campo. In un contesto ideale, i dati sul campo di un fornitore di monitoraggio in tempo reale degli utenti (RUM) forniscono non solo il valore INP di una pagina, ma anche dati contestuali che mettono in evidenza l'interazione specifica responsabile del valore INP stesso, se l'interazione si è verificata durante o dopo il caricamento della pagina, il tipo di interazione (clic, pressione dei tasti o tocco) e altre informazioni utili.

Se non utilizzi un fornitore RUM per ottenere i dati sul campo, la guida ai dati sul campo INP consiglia di utilizzare il Report sull'esperienza utente di Chrome (CrUX) tramite PageSpeed Insights per colmare le lacune. CrUX è il set di dati ufficiale del programma Core Web Vitals e fornisce un riepilogo generale delle metriche per milioni di siti web, inclusa la metrica INP. Tuttavia, CrUX spesso non fornisce i dati contestuali che otterresti da un provider RUM per aiutarti ad analizzare i problemi. Per questo motivo, consigliamo comunque ai siti di utilizzare un fornitore RUM, se possibile, o di implementare la propria soluzione RUM per integrare ciò che è disponibile in CrUX.

Diagnostica le interazioni lente nel lab

Idealmente, ti consigliamo di iniziare a eseguire i test in laboratorio quando disponi di dati sul campo che suggeriscono interazioni lente. In assenza di dati sul campo, esistono alcune strategie per identificare le interazioni lente in laboratorio. Queste strategie includono il seguire flussi utente comuni e il test delle interazioni lungo il percorso, nonché l'interazione con la pagina durante il caricamento, quando il thread principale è spesso più impegnato, per rilevare le interazioni lente durante questa parte cruciale dell'esperienza utente.

Ottimizzare le interazioni

Una volta identificata un'interazione lenta e riprodotta manualmente nel lab, il passaggio successivo consiste nell'ottimizzarla. Le interazioni possono essere suddivise in tre fasi:

  1. Il ritardo di input, che inizia quando l'utente avvia un'interazione con la pagina e termina quando iniziano a essere eseguiti i callback dell'evento per l'interazione.
  2. La durata dell'elaborazione, che consiste nel tempo necessario per l'esecuzione completa dei callback degli eventi.
  3. Il ritardo di visualizzazione, ovvero il tempo necessario al browser per presentare il frame successivo contenente il risultato visivo dell'interazione.

La somma di queste tre fasi è la latenza di interazione totale. Ogni singola fase di un'interazione contribuisce a un determinato periodo di tempo alla latenza totale dell'interazione, pertanto è importante sapere come ottimizzare ogni parte dell'interazione in modo che venga eseguita nel minor tempo possibile.

Identificare e ridurre il ritardo di input

Quando un utente interagisce con una pagina, la prima parte dell'interazione è il ritardo di input. A seconda di altre attività nella pagina, i ritardi di inserimento possono essere considerevoli. Ciò potrebbe essere dovuto all'attività che si verifica nel thread principale (ad esempio a causa del caricamento, dell'analisi e della compilazione degli script), alla gestione del recupero, alle funzioni del timer o anche ad altre interazioni che si verificano in rapida successione e si sovrappongono.

Indipendentemente dalla fonte del ritardo di input di un'interazione, ti consigliamo di ridurlo al minimo in modo che le interazioni possano iniziare a eseguire i callback degli eventi il prima possibile.

La relazione tra la valutazione dello script e le attività lunghe durante l'avvio

Un aspetto fondamentale dell'interattività nel ciclo di vita della pagina è durante l'avvio. Quando una pagina viene caricata, viene inizialmente visualizzata, ma è importante ricordare che il semplice fatto che una pagina sia stata visualizzata non significa che il caricamento sia terminato. A seconda del numero di risorse necessarie per rendere una pagina completamente funzionale, è possibile che gli utenti tenti di interagire con la pagina mentre è ancora in corso il caricamento.

Un fattore che può prolungare il ritardo di inserimento di un'interazione durante il caricamento di una pagina è la valutazione dello script. Dopo aver recuperato un file JavaScript dalla rete, il browser ha ancora del lavoro da fare prima che il codice JavaScript possa essere eseguito; questo lavoro include l'analisi di uno script per assicurarsi che la sintassi sia valida, la compilazione in bytecode e infine l'esecuzione.

A seconda delle dimensioni di uno script, questa operazione può introdurre attività lunghe nel thread principale, il che ritarderà la risposta del browser ad altre interazioni utente. Per mantenere la pagina reattiva all'input dell'utente durante il caricamento, è importante capire cosa puoi fare per ridurre la probabilità di attività lunghe durante il caricamento in modo che la pagina rimanga scattante.

Ottimizzare i callback eventi

Il ritardo di input è solo la prima parte di ciò che viene misurato dall'INP. Inoltre, devi assicurarti che i callback degli eventi eseguiti in risposta a un'interazione utente possano essere completati il più rapidamente possibile.

Rinuncia spesso al thread principale

Il miglior consiglio generale per ottimizzare i callback degli eventi è di eseguire il minor lavoro possibile al loro interno. Tuttavia, la logica di interazione potrebbe essere complessa e potresti riuscire a ridurre solo marginalmente il lavoro svolto.

Se questo è il caso del tuo sito web, puoi provare a suddividere il lavoro nei callback degli eventi in attività separate. In questo modo, il lavoro collettivo non diventa un'attività lunga che blocca il thread principale, il che consente di eseguire prima altre interazioni che altrimenti rimarrebbero in attesa nel thread principale.

setTimeout è un modo per suddividere le attività, perché il callback passato viene eseguito in una nuova attività. Puoi utilizzare setTimeout da solo o estrarne l'utilizzo in una funzione separata per un rendimento più ergonomico.

È meglio cedere il controllo in modo indiscriminato rispetto a non cederlo affatto. Tuttavia, esiste un modo più sofisticato per cedere il controllo al thread principale, che prevede di cedere il controllo solo immediatamente dopo un callback evento che aggiorna l'interfaccia utente in modo che la logica di rendering possa essere eseguita prima.

Rinuncia per consentire l'esecuzione del rendering in anticipo

Una tecnica di rendimento più avanzata prevede la strutturazione del codice nei callback degli eventi per limitare l'esecuzione solo alla logica necessaria per applicare gli aggiornamenti visivi per il fotogramma successivo. Tutto il resto può essere posticipato a un'attività successiva. In questo modo, non solo i callback rimangono leggeri e agili, ma migliorano anche i tempi di rendering per le interazioni impedendo che gli aggiornamenti visivi blocchino il codice del callback dell'evento.

Ad esempio, immagina un editor di testo avanzato che formatta il testo mentre digiti, ma aggiorna anche altri aspetti dell'interfaccia utente in base a ciò che hai scritto (ad esempio il numero di parole, l'evidenziazione degli errori ortografici e altri feedback visivi importanti). Inoltre, l'applicazione potrebbe dover salvare ciò che hai scritto in modo che, se esci e torni, non perdano il lavoro.

In questo esempio, in risposta ai caratteri digitati dall'utente devono verificarsi le seguenti quattro azioni. Tuttavia, prima di visualizzare il frame successivo, è necessario completare solo il primo elemento.

  1. Aggiorna la casella di testo con il testo digitato dall'utente e applica la formattazione richiesta.
  2. Aggiorna la parte dell'interfaccia utente che mostra il numero corrente di parole.
  3. Esegui la logica per verificare la presenza di errori ortografici.
  4. Salva le modifiche più recenti (localmente o in un database remoto).

Il codice per eseguire questa operazione potrebbe avere il seguente aspetto:

textBox.addEventListener('input', (inputEvent) => {
  // Update the UI immediately, so the changes the user made
  // are visible as soon as the next frame is presented.
  updateTextBox(inputEvent);

  // Use `setTimeout` to defer all other work until at least the next
  // frame by queuing a task in a `requestAnimationFrame()` callback.
  requestAnimationFrame(() => {
    setTimeout(() => {
      const text = textBox.textContent;
      updateWordCount(text);
      checkSpelling(text);
      saveChanges(text);
    }, 0);
  });
});

La seguente visualizzazione mostra come il differimento di eventuali aggiornamenti non critici fino al frame successivo può ridurre la durata dell'elaborazione e quindi la latenza di interazione complessiva.

Raffigurazione di un'interazione con la tastiera e le attività successive in due scenari. Nella figura in alto, l'attività di rendering critico e tutte le attività in background successive vengono eseguite in modo sincrono fino a quando non si presenta l'opportunità di presentare un frame. Nella figura in basso, il lavoro critico per il rendering viene eseguito per primo, quindi cede il posto al thread principale per presentare prima un nuovo frame. Le attività in background vengono eseguite in seguito.
Fai clic sull'immagine qui sopra per visualizzare una versione ad alta risoluzione.

Sebbene l'utilizzo di setTimeout() all'interno di una chiamata requestAnimationFrame() nell'esempio di codice precedente sia un po' criptico, si tratta di un metodo efficace che funziona in tutti i browser per garantire che il codice non critico non blocchi il frame successivo.

Evitare il thrashing del layout

Il thrashing del layout, a volte chiamato layout sincrono forzato, è un problema di prestazioni di rendering in cui il layout avviene in modo sincrono. Si verifica quando aggiorni gli stili in JavaScript e poi li leggi nella stessa attività. Esistono molte proprietà in JavaScript che possono causare il thrashing del layout.

Una visualizzazione del thrashing del layout, come mostrato nel riquadro Rendimento di Chrome DevTools.
Un esempio di thrashing del layout, come mostrato nel riquadro delle prestazioni di Chrome DevTools. Le attività di rendering che comportano un riavvolgimento del layout verranno contrassegnate da un triangolo rosso nell'angolo in alto a destra della parte dello stack di chiamate, spesso etichettata come Ricalcolo stile o Layout.

Il thrashing del layout è un collo di bottiglia delle prestazioni perché, aggiornando gli stili e richiedendo immediatamente i valori di questi stili in JavaScript, il browser è costretto a eseguire operazioni di layout sincrone che altrimenti avrebbe potuto eseguire in modo asincrono in un secondo momento, dopo l'esecuzione dei callback degli eventi.

Riduci al minimo il ritardo della presentazione

Il ritardo di visualizzazione di un'interazione va dal termine dell'esecuzione dei richiami di evento di un'interazione fino al punto in cui il browser è in grado di disegnare il frame successivo che mostra le modifiche visive risultanti.

Riduci al minimo le dimensioni del DOM

Quando il DOM di una pagina è piccolo, il rendering di solito termina rapidamente. Tuttavia, quando i DOM diventano molto grandi, il lavoro di rendering tende ad aumentare con le dimensioni del DOM. La relazione tra il lavoro di rendering e le dimensioni del DOM non è lineare, ma i DOM di grandi dimensioni richiedono più lavoro per il rendering rispetto ai DOM di piccole dimensioni. Un DOM di grandi dimensioni è problematico in due casi:

  1. Durante il rendering iniziale della pagina, quando un DOM di grandi dimensioni richiede molto lavoro per il rendering dello stato iniziale della pagina.
  2. In risposta a un'interazione dell'utente, un DOM di grandi dimensioni può causare aggiornamenti di rendering molto costosi e, di conseguenza, aumentare il tempo necessario al browser per presentare il frame successivo.

Tieni presente che in alcuni casi i DOM di grandi dimensioni non possono essere ridotti in modo significativo. Sebbene esistano approcci che puoi adottare per ridurre le dimensioni del DOM, ad esempio appiattire il DOM o aggiungere elementi al DOM durante le interazioni degli utenti per mantenere piccole le dimensioni iniziali del DOM, queste tecniche possono essere efficaci solo fino a un certo punto.

Utilizzare content-visibility per eseguire il rendering lento degli elementi fuori dallo schermo

Un modo per limitare la quantità di lavoro di rendering durante il caricamento della pagina e in risposta alle interazioni degli utenti è fare affidamento sulla proprietà CSS content-visibility, che equivale a eseguire il rendering degli elementi in modo lazy quando si avvicinano all'area visibile. Anche se l'utilizzo efficace di content-visibility richiede un po' di pratica, vale la pena verificare se il risultato è un tempo di rendering inferiore che può migliorare l'INP della tua pagina.

Tieni conto dei costi di prestazioni durante il rendering dell'HTML utilizzando JavaScript

Dove c'è HTML, c'è l'analisi dell'HTML e, dopo che il browser ha terminato di analizzare l'HTML in un DOM, deve applicare gli stili, eseguire calcoli di layout e successivamente eseguire il rendering del layout. Si tratta di un costo inevitabile, ma è importante come esegui il rendering dell'HTML.

Quando il server invia HTML, questo arriva nel browser sotto forma di stream. Lo streaming indica che la risposta HTML del server arriva a blocchi. Il browser ottimizza il modo in cui gestisce uno stream analizzando in modo incrementale i relativi blocchi man mano che arrivano e visualizzandoli bit per bit. Si tratta di un'ottimizzazione delle prestazioni in quanto il browser si arresta implicitamente periodicamente e automaticamente durante il caricamento della pagina e puoi usufruirne senza costi.

Sebbene la prima visita a qualsiasi sito web implichi sempre un po' di codice HTML, un approccio comune inizia con un bit iniziale minimo di HTML, quindi viene utilizzato JavaScript per compilare l'area dei contenuti. Anche gli aggiornamenti successivi dell'area dei contenuti si verificano in seguito alle interazioni degli utenti. Questo è in genere chiamato modello di applicazione a pagina singola (APS). Uno svantaggio di questo pattern è che, eseguendo il rendering dell'HTML con JavaScript sul client, non solo si ha il costo dell'elaborazione di JavaScript per creare l'HTML, ma anche il browser non restituirà nulla finché non avrà terminato l'analisi e il rendering dell'HTML.

È però fondamentale ricordare che anche i siti web che non sono SPA probabilmente prevedono una certa quantità di rendering HTML tramite JavaScript come risultato delle interazioni. In genere, questo non è un problema, a condizione che non vengano visualizzate grandi quantità di codice HTML sul client, il che può ritardare la presentazione del frame successivo. Tuttavia, è importante comprendere le implicazioni sul rendimento di questo approccio al rendering dell'HTML nel browser e in che modo può influire sulla reattività del tuo sito web all'input degli utenti se esegui il rendering di molto HTML tramite JavaScript.

Conclusione

Il miglioramento dell'INP del tuo sito è un processo iterativo. Quando correggi un'interazione lenta sul campo, è probabile che, soprattutto se il tuo sito web offre molta interattività, inizierai a trovare altre interazioni lente che dovrai ottimizzare.

La chiave per migliorare l'INP è la persistenza. Nel tempo, puoi migliorare la reattività della tua pagina in modo che gli utenti siano soddisfatti dell'esperienza che offri. È anche probabile che, durante lo sviluppo di nuove funzionalità per i tuoi utenti, tu debba seguire la stessa procedura per ottimizzare le interazioni specifiche per loro. Richiederà tempo e impegno, ma ne varrà la pena.

Immagine hero di Unsplash, di David Pisnoy e modificata in conformità con la licenza Unsplash.