content-visibility: la nuova proprietà CSS che migliora le prestazioni del rendering

Migliora il tempo di caricamento iniziale ignorando il rendering dei contenuti offscreen.

Vladimir Levin
Vladimir Levin

Data di pubblicazione: 5 agosto 2020

La proprietà content-visibility consente allo user agent di saltare il lavoro di rendering di un elemento, inclusi layout e pittura, finché non è necessario. Poiché il rendering viene saltato, se una grande parte dei contenuti non è visibile sullo schermo, l'utilizzo della proprietà content-visibility consente di velocizzare notevolmente il caricamento iniziale dell'utente. Inoltre, consente di interagire più rapidamente con i contenuti sullo schermo. Molto interessante.

Supporto dei browser

  • Chrome: 85.
  • Edge: 85.
  • Firefox: 125.
  • Safari: 18.

Origine

demo con figure che rappresentano i risultati di rete
Nella demo dell'articolo, l'applicazione di content-visibility: auto alle aree di contenuti suddivise in blocchi consente di migliorare le prestazioni di rendering di 7 volte al caricamento iniziale. Continua a leggere per saperne di più.

Contenimento CSS

L'obiettivo principale e generale del contenimento CSS è consentire il miglioramento del rendimento del rendering dei contenuti web garantendo l'isolamento prevedibile di un sottoalbero DOM dal resto della pagina.

In sostanza, uno sviluppatore può dire a un browser quali parti della pagina sono incapsulate come insieme di contenuti, consentendo ai browser di ragionare sui contenuti senza dover prendere in considerazione lo stato al di fuori del sottoalbero. Sapere quali parti di contenuti (sottoalberi) contengono contenuti isolati significa che il browser può prendere decisioni di ottimizzazione per il rendering della pagina.

Esistono quattro tipi di contenimento CSS, ciascuno un potenziale valore per la proprietà CSS contain, che può essere combinato in un elenco di valori separati da spazi:

  • size: il contenimento delle dimensioni su un elemento garantisce che la scatola dell'elemento possa essere disposta senza dover esaminare i relativi discendenti. Ciò significa che possiamo potenzialmente saltare il layout dei discendenti se tutto ciò di cui abbiamo bisogno è la dimensione dell'elemento.
  • layout: il contenimento del layout indica che i discendenti non influiscono sul layout esterno di altre caselle nella pagina. In questo modo possiamo potenzialmente saltare il layout dei discendenti se vogliamo solo disporre altre caselle.
  • style: il contenimento degli stili garantisce che le proprietà che possono avere effetti su più elementi oltre ai suoi discendenti non escano dall'elemento (ad es. i contatori). In questo modo, possiamo potenzialmente saltare il calcolo degli stili per i discendenti se vogliamo solo calcolare gli stili su altri elementi.
  • paint: il contenimento della pittura garantisce che i discendenti della casella contenente non vengano visualizzati al di fuori dei relativi limiti. Nessun elemento può fuoriuscire dall'elemento, e se un elemento è fuori dallo schermo o non è visibile, anche i suoi discendenti non saranno visibili. In questo modo potremo saltare la pittura dei discendenti se l'elemento è fuori schermo.

Ignorare il lavoro di rendering con content-visibility

Può essere difficile capire quali valori di contenimento utilizzare, poiché le ottimizzazioni del browser possono essere attivate solo quando viene specificato un insieme appropriato. Puoi sperimentare con i valori per vedere qual è il migliore oppure puoi utilizzare content-visibility per applicare automaticamente il contenimento necessario. content-visibility ti garantisce i maggiori guadagni in termini di rendimento che il browser può offrire con il minimo sforzo da parte tua come sviluppatore.

La proprietà visibilità-contenuti accetta diversi valori, ma auto è quella che offre miglioramenti immediati del rendimento. Un elemento che ha content-visibility: auto acquisisce il contenimento di layout, style e paint. Se l'elemento è fuori dallo schermo (e non è altrimenti pertinente per l'utente; gli elementi pertinenti sono quelli che hanno lo stato attivo o di selezione nel sottoalbero), acquisisce anche il contenimento size (e interrompe la disegnatura e test di hit dei suoi contenuti).

Che cosa significa? In breve, se l'elemento è fuori dallo schermo, i suoi discendenti non vengono visualizzati. Il browser determina le dimensioni dell'elemento senza considerare alcuno dei suoi contenuti e si ferma qui. La maggior parte del rendering, come lo stile e il layout del sottoalbero dell'elemento, viene saltata.

Quando l'elemento si avvicina all'area visibile, il browser non aggiunge più il contenuto size e inizia a dipingere e eseguire l'hit test dei contenuti dell'elemento. In questo modo, il rendering viene eseguito appena in tempo per essere visualizzato dall'utente.

Una nota sull'accessibilità

Una delle funzionalità di content-visibility: auto è che i contenuti off-screen rimangono disponibili nel modello a oggetti del documento e, di conseguenza, nella struttura ad albero di accessibilità (a differenza di visibility: hidden). Ciò significa che i contenuti possono essere cercati nella pagina e visualizzati senza attendere il caricamento o sacrificare le prestazioni di rendering.

Il rovescio della medaglia, però, è che gli elementi landmark con funzionalità di stile come display: none o visibility: hidden vengono visualizzati anche nella struttura ad albero di accessibilità quando non sono sullo schermo, poiché il browser non li esegue fino a quando non entrano nell'area visibile. Per evitare che siano visibili nella struttura ad accesso facilitato, causando potenzialmente confusione, assicurati di aggiungere anche aria-hidden="true".

Esempio: un blog di viaggi

In questo esempio, abbiamo basato il nostro blog di viaggi a destra e applichiamo content-visibility: auto ad aree suddivise a sinistra. I risultati mostrano tempi di rendering compresi tra 232 ms e 30 ms al caricamento iniziale della pagina.

Un blog di viaggi in genere contiene una serie di storie con alcune immagini e un testo descrittivo. Ecco cosa succede in un browser tipico quando accede a un blog di viaggi:

  1. Una parte della pagina viene scaricata dalla rete, insieme a tutte le risorse necessarie.
  2. Il browser applica uno stile e un layout a tutti i contenuti della pagina, senza considerare se i contenuti sono visibili all'utente.
  3. Il browser torna al passaggio 1 finché non vengono scaricate tutte le risorse e la pagina.

Nel passaggio 2, il browser elabora tutti i contenuti cercando elementi che potrebbero essere stati modificati. Aggiorna lo stile e il layout di tutti i nuovi elementi, nonché degli elementi che potrebbero essere stati spostati a seguito di nuovi aggiornamenti. Si tratta del lavoro di rendering. Questa operazione richiede tempo.

Uno screenshot di un blog di viaggi.
Un esempio di blog di viaggi. Guarda la demo su Codepen

Ora considera cosa succede se inserisci content-visibility: auto in ogni singola storia del blog. Il loop generale è lo stesso: il browser scarica e visualizza parti della pagina. Tuttavia, la differenza sta nella quantità di lavoro che svolge nel passaggio 2.

Con la visibilità dei contenuti, vengono impostati lo stile e il layout di tutti i contenuti attualmente visibili all'utente (sullo schermo). Tuttavia, durante l'elaborazione della storia completamente fuori dallo schermo, il browser salta il lavoro di rendering e applica solo lo stile e il layout della casella dell'elemento.

Il rendimento del caricamento di questa pagina sarebbe come se contenesse storie sullo schermo complete e caselle vuote per ciascuna delle storie off-screen. Il rendimento è molto migliore, con una riduzione prevista del 50% o più del costo di rendering del caricamento. Nel nostro esempio, registriamo un miglioramento da un tempo di rendering di 232 ms a un tempo di rendering di 30 ms. Ciò corrisponde a un aumento delle prestazioni di 7 volte.

Quali sono le operazioni che devi svolgere per usufruire di questi vantaggi? Innanzitutto, suddividiamo i contenuti in sezioni:

Uno screenshot con annotazioni del chunking dei contenuti in sezioni con una classe CSS.
Esempio di suddivisione dei contenuti in sezioni con l'applicazione della classe story per ricevere content-visibility: auto. Vedi Demo su Codepen

Poi applichiamo la seguente regola di stile alle sezioni:

.story {
  content-visibility: auto;
  contain-intrinsic-size: 1000px; /* Explained in the next section. */
}

Specifica le dimensioni naturali di un elemento con contain-intrinsic-size

Per realizzare i potenziali vantaggi di content-visibility, il browser deve applicare il contenimento delle dimensioni per assicurarsi che i risultati di rendering dei contenuti non influiscano in alcun modo sulle dimensioni dell'elemento. Ciò significa che l'elemento verrà visualizzato come se fosse vuoto. Se per l'elemento non è specificata un'altezza in un layout di blocco regolare, l'altezza sarà pari a 0.

Questo potrebbe non essere l'ideale, poiché la dimensione della barra di scorrimento cambierà, dipendendo da ogni storia con un'altezza diversa da zero.

Fortunatamente, il CSS fornisce un'altra proprietà, contain-intrinsic-size, che specifica in modo efficace le dimensioni naturali dell'elemento se l'elemento è interessato dal contenimento delle dimensioni. Nel nostro esempio, lo impostiamo su 1000px come stima dell'altezza e della larghezza delle sezioni.

Ciò significa che verrà visualizzato come se avesse un singolo elemento figlio delle dimensioni "dimensioni-intrinseche", garantendo che i div senza dimensioni occupino comunque spazio. contain-intrinsic-size funge da dimensione segnaposto al posto dei contenuti visualizzati.

La parola chiave auto per contain-intrinsic-size fa in modo che il browser ricordi le dimensioni dell'ultima rappresentazione, se esistenti, e le utilizzi al posto delle dimensioni del segnaposto fornite dallo sviluppatore. Ad esempio, se hai specificato contain-intrinsic-size: auto 300px, l'elemento inizierà con una dimensione intrinseca 300px in ogni dimensione, ma una volta visualizzati i contenuti dell'elemento, manterrà la dimensione intrinseca visualizzata. Verranno memorizzate anche eventuali modifiche successive alle dimensioni di rendering. In pratica, ciò significa che se scorri un elemento con content-visibility: auto applicato e poi lo scorri di nuovo fuori schermo, l'elemento manterrà automaticamente la larghezza e l'altezza ideali e non verrà ripristinato le dimensioni del segnaposto. Questa funzionalità è particolarmente utile per gli annunci con scorrimento infinito, che ora possono migliorare automaticamente la stima delle dimensioni nel tempo man mano che l'utente esplora la pagina.

Nascondere i contenuti con content-visibility: hidden

Cosa succede se vuoi che i contenuti non vengano sottoposti a rendering indipendentemente dal fatto che siano visualizzati o meno sullo schermo, sfruttando al contempo i vantaggi dello stato di rendering memorizzato nella cache? Inserisci: content-visibility: hidden.

La proprietà content-visibility: hidden offre gli stessi vantaggi dei contenuti non visualizzati e dello stato di rendering memorizzato nella cache di content-visibility: auto al di fuori dello schermo. Tuttavia, a differenza di auto, la visualizzazione sullo schermo non inizia automaticamente.

In questo modo, hai un maggiore controllo, puoi nascondere i contenuti di un elemento e in seguito mostrarli rapidamente.

Confrontalo con altri modi comuni per nascondere i contenuti degli elementi:

  • display: none: nasconde l'elemento e ne distrugge lo stato di rendering. Ciò significa che mostrare l'elemento è costoso quanto il rendering di un nuovo elemento con gli stessi contenuti.
  • visibility: hidden: nasconde l'elemento e ne mantiene lo stato di rendering. In questo modo, l'elemento non viene effettivamente rimosso dal documento, in quanto (e il relativo sottoalbero) occupano ancora spazio geometrico nella pagina e possono essere ancora selezionati. Inoltre, aggiorna lo stato di rendering ogni volta che è necessario, anche quando è nascosto.

content-visibility: hidden, invece, nasconde l'elemento mantenendone lo stato di rendering, pertanto, se devono essere apportate modifiche, queste vengono applicate solo quando l'elemento viene mostrato di nuovo (ovvero quando la proprietà content-visibility: hidden viene rimossa).

Alcuni casi d'uso interessanti per content-visibility: hidden sono l'implementazione di scorrevoli virtuali avanzati e la misurazione del layout. Sono inoltre ideali per le applicazioni a pagina singola (SPA). Le visualizzazioni di app non attive possono essere lasciate nel DOM concontent-visibility: hidden applicato per impedirne la visualizzazione, ma mantenendone lo stato memorizzato nella cache. In questo modo, la visualizzazione viene visualizzata rapidamente quando diventa di nuovo attiva.

Effetti sull’interazione con Next Paint (INP)

L'INP è una metrica che valuta la capacità di una pagina di rispondere in modo affidabile all'input utente. La reattività può essere influenzata da un'eccessiva quantità di lavoro che si verifica nel thread principale, incluso il lavoro di rendering.

Ogni volta che puoi ridurre il lavoro di rendering su una determinata pagina, offri al thread principale l'opportunità di rispondere più rapidamente agli input degli utenti. Sono inclusi i lavori di rendering e, se opportuno, l'utilizzo della proprietà CSS content-visiblity può ridurli, in particolare durante l'avvio, quando viene eseguita la maggior parte del lavoro di rendering e layout.

La riduzione del lavoro di rendering ha un effetto diretto sull'INP. Quando gli utenti tentano di interagire con una pagina che utilizza correttamente la proprietà content-visibility per posticipare il layout e il rendering degli elementi offscreen, offri al thread principale la possibilità di rispondere a un'attività critica visibile all'utente. In alcuni casi, questo può migliorare l'INP della tua pagina.

Conclusione

content-visibility e la specifica di contenimento CSS indicano che alcune ottimizzazioni del rendimento interessanti sono in arrivo nel tuo file CSS. Per ulteriori informazioni su queste proprietà, dai un'occhiata a: