Evita vernici inutili

Paul Lewis

Introduzione

La pittura degli elementi di un sito o di un'applicazione può essere molto costosa e può avere un effetto domino negativo sulle prestazioni di runtime. In questo articolo diamo un'occhiata veloce a cosa può attivare la pittura nel browser e a come puoi impedire la realizzazione di pitture non necessarie.

Pittura: un tour super veloce

Una delle principali attività che un browser deve svolgere è convertire il DOM e il CSS in pixel sullo schermo e lo fa attraverso un processo abbastanza complesso. Inizia leggendo il markup e da questo crea una struttura DOM. Fa una cosa simile con il CSS e da qui crea il CSSOM. Il DOM e il CSSOM vengono quindi combinati e, alla fine, arriviamo a una struttura da cui possiamo iniziare a dipingere alcuni pixel.

Il processo di pittura stesso è interessante. In Chrome, l'albero combinato di DOM e CSS viene rasterizzato da un software chiamato Skia. Se hai mai utilizzato l'elemento canvas, l'API di Skia ti sembrerà molto familiare; sono disponibili molte funzioni in stile moveTo e lineTo, oltre a una serie di funzioni più avanzate. In sostanza, tutti gli elementi che devono essere dipinti vengono distillati in una raccolta di chiamate Skia che possono essere eseguite e l'output è un insieme di bitmap. Queste bitmap vengono caricate nella GPU e la GPU è utile componendole insieme per fornirci l'immagine finale sullo schermo.

Dom a pixel

È importante sottolineare che il carico di lavoro di Skia dipende direttamente dagli stili che applichi agli elementi. Se utilizzi stili algoritmici complessi, Skia avrà più lavoro da fare. Colt McAnlis ha scritto un articolo su come il CSS influisce sul peso del rendering della pagina, quindi ti consigliamo di leggerlo per saperne di più.

Detto questo, l'applicazione della vernice richiede tempo e, se non la riduciamo, supereremo il budget del frame di circa 16 ms. Gli utenti noteranno che abbiamo perso i frame e li vedranno come jank, che alla fine danneggiano l'esperienza utente della nostra app. Non vogliamo davvero, quindi vediamo quali tipi di elementi comportano la necessità di un intervento di verniciatura e cosa possiamo fare al riguardo.

Scorrimento

Ogni volta che scorri verso l'alto o verso il basso nel browser, i contenuti devono essere ridisegnati prima di essere visualizzati sullo schermo. Se tutto va bene, si tratterà di una piccola area, ma anche in questo caso agli elementi da disegnare potrebbero essere applicati stili complessi. Quindi, anche se hai una piccola area da dipingere, non significa che il lavoro verrà svolto rapidamente.

Per vedere quali aree vengono ridisegnate, puoi utilizzare la funzionalità "Mostra rettangoli di pittura" in DevTools di Chrome (basta fare clic sul piccolo ingranaggio nell'angolo in basso a destra). Dopodiché, con DevTools aperto, interagisci con la pagina e vedrai dei rettangoli lampeggianti che mostrano dove e quando Chrome ha dipinto una parte della pagina.

Mostrare i rettangoli colorati in Chrome DevTools
Mostrare i rettangoli di pittura in Chrome DevTools

Le prestazioni di scorrimento sono fondamentali per il successo del tuo sito. Gli utenti notano molto quando il tuo sito o la tua applicazione non scorre bene e non gli piace. Pertanto, abbiamo un interesse diretto a mantenere leggero il lavoro di pittura durante lo scorrimento in modo che gli utenti non vedano scatti.

In precedenza ho scritto un articolo sulle prestazioni dello scorrimento, quindi consultalo se vuoi saperne di più sulle prestazioni dello scorrimento.

Interazioni

Un'altra causa del colore sono le interazioni: passaggi con il mouse, clic, tocchi, trascinamenti. Ogni volta che l'utente esegue una di queste interazioni, ad esempio passando il mouse sopra, Chrome dovrà ricreare l'elemento interessato. Come per lo scorrimento, se è richiesta una pittura grande e complessa, la frequenza frame diminuirà.

Tutti vogliono animazioni di interazione piacevoli e fluide, quindi dovremo capire se gli stili che cambiano nella nostra animazione ci stanno facendo perdere troppo tempo.

Una combinazione sfortunata

Una demo con vernici costose
Una demo con vernici costose

Che cosa succede se scorro e contemporaneamente muovo il mouse? È perfettamente possibile che io inadvertentemente "interagisca" con un elemento mentre scorro, attivando una pittura costosa. Ciò, a sua volta, potrebbe superare il mio budget di frame di circa 16,7 ms (il tempo che dobbiamo mantenere al di sotto per raggiungere i 60 frame al secondo). Ho creato una demo per mostrarti esattamente cosa intendo. Speriamo che, mentre scorri e muovi il mouse, vedrai gli effetti di passaggio del mouse, ma vediamo cosa ne pensano gli Strumenti per sviluppatori di Chrome:

Chrome DevTools mostra frame costosi
Chrome DevTools mostra frame costosi

Nell'immagine qui sopra puoi vedere che DevTools sta registrando il disegno quando passo il mouse sopra uno dei blocchi. Ho scelto alcuni stili molto pesanti nella mia demo per farti capire il punto, quindi sto raggiungendo e a volte superando il mio budget di frame. L'ultima cosa che voglio è dover fare questa operazione di pittura inutilmente, soprattutto durante lo scorrimento quando c'è altro lavoro da fare.

Come possiamo evitare che ciò accada? In questo caso, la correzione è piuttosto semplice da implementare. Il trucco è associare un gestore scroll che disattivi gli effetti di passaggio del mouse e imposti un timer per riattivarli. Ciò significa che, quando l'utente scorre la pagina, non sarà necessario eseguire costose immagini di interazione. Quando ti fermi per un tempo sufficiente, decidiamo che è possibile riattivarle.

Ecco il codice:

// Used to track the enabling of hover effects
var enableTimer = 0;

/*
 * Listen for a scroll and use that to remove
 * the possibility of hover effects
 */
window.addEventListener('scroll', function() {
  clearTimeout(enableTimer);
  removeHoverClass();

  // enable after 1 second, choose your own value here!
  enableTimer = setTimeout(addHoverClass, 1000);
}, false);

/**
 * Removes the hover class from the body. Hover styles
 * are reliant on this class being present
 */
function removeHoverClass() {
  document.body.classList.remove('hover');
}

/**
 * Adds the hover class to the body. Hover styles
 * are reliant on this class being present
 */
function addHoverClass() {
  document.body.classList.add('hover');
}

Come puoi vedere, utilizziamo una classe nel corpo per monitorare se gli effetti di passaggio del mouse sono "consentiti" o meno e gli stili sottostanti si basano sulla presenza di questa classe:

/* Expect the hover class to be on the body
 before doing any hover effects */
.hover .block:hover {
 
}

E questo è tutto!

Conclusione

Le prestazioni del rendering sono fondamentali per gli utenti che apprezzano la tua applicazione e dovresti sempre cercare di mantenere il carico di lavoro di colorazione al di sotto di 16 ms. Per aiutarti a farlo, devi integrare l'utilizzo di DevTools durante tutto il processo di sviluppo per identificare e correggere i colli di bottiglia man mano che si presentano.

Le interazioni involontarie, in particolare con elementi con molto colore, possono essere molto costose e influire negativamente sulle prestazioni di rendering. Come hai visto, possiamo utilizzare un piccolo pezzo di codice per risolvere il problema.

Dai un'occhiata ai tuoi siti e alle tue applicazioni. Potrebbero avere bisogno di un po' di protezione della vernice?