⚡ Prestazioni web

CSS inutilizzato e CSS critico: alleggerire i fogli di stile

Come scoprire quanto CSS la pagina non usa, eliminarlo in sicurezza, estrarre gli stili critici e caricare il resto senza bloccare il primo rendering.

Il CSS blocca il rendering: finché il browser non ha scaricato e analizzato tutti i fogli di stile collegati nell'intestazione, non disegna nulla. È una scelta sensata, perché mostrare una pagina senza stili per poi ridisegnarla sarebbe peggio. Il problema nasce quando quel CSS pesa centinaia di kilobyte, di cui la pagina usa una piccola parte. Succede quasi sempre con temi grafici generici, framework completi inclusi per intero e anni di stili accumulati senza mai togliere nulla.

Misurare il CSS inutilizzato

In Chrome DevTools il pannello «Copertura» (Coverage) registra quali byte di CSS e JavaScript vengono effettivamente usati. Si apre dal menu dei comandi, si avvia la registrazione e si ricarica la pagina. Il risultato è una tabella con la percentuale di codice non usato per ogni file e, cliccando su un file, le righe evidenziate in rosso.

Due cautele nell'interpretare i numeri:

  • la copertura riguarda solo ciò che è successo durante la registrazione. Gli stili di un menu aperto, di un modulo con errori, di una finestra modale o di un'altra larghezza dello schermo risultano inutilizzati se non sono stati attivati;
  • un foglio usato al 30% su una pagina può essere usato al 70% su un'altra. Bisogna ragionare sull'insieme delle pagine, non su una sola.

Conviene quindi registrare, interagire con la pagina (aprire menu, ridimensionare, compilare moduli) e ripetere su più modelli di pagina.

Rimuovere il CSS che non serve

Alla fonte

La strada più pulita è non includerlo. Molti framework permettono di importare solo i moduli usati: griglia, tipografia e pulsanti, senza caroselli, tooltip e componenti mai impiegati. Nei progetti con preprocessori basta commentare le importazioni superflue nel file principale.

Con strumenti di eliminazione

Strumenti come PurgeCSS analizzano i file HTML e i modelli del progetto, raccolgono i nomi di classi e selettori presenti e rimuovono dal CSS quelli che non compaiono. Il rischio è eliminare classi generate dinamicamente da JavaScript, per esempio:

elemento.classList.add('stato-' + stato);   // 'stato-attivo', 'stato-errore'

Lo strumento non vede «stato-attivo» nel codice e lo elimina. Per questo esistono le liste di sicurezza (safelist) in cui dichiarare classi o schemi da conservare:

safelist: [/^stato-/, 'aperto', 'visibile']

Le librerie di utilità come Tailwind adottano l'approccio inverso: generano solo le classi effettivamente trovate nei sorgenti, quindi il problema si presenta meno, a patto di non comporre nomi di classe con concatenazioni di stringhe.

Estrarre il CSS critico

Il CSS critico è l'insieme minimo di regole necessario a disegnare la parte visibile della pagina all'apertura: intestazione, menu, titolo, primo blocco di contenuto. L'idea è:

  1. incorporare queste regole in un tag style nell'HTML, così non serve un viaggio di rete per mostrarle;
  2. caricare il resto del CSS senza bloccare il rendering;
  3. lasciare che il foglio completo arrivi e si applichi poco dopo.

Un modo diffuso per caricare il foglio non critico:

<style>/* regole critiche incorporate */</style>
<link rel="preload" href="/css/completo.css" as="style"
      onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/css/completo.css"></noscript>

Esistono strumenti che estraggono automaticamente le regole critiche aprendo la pagina in un browser senza interfaccia a una o più dimensioni di viewport.

Quando non conviene

Il CSS critico ha un costo: le regole incorporate non vengono memorizzate in cache e si ripetono in ogni pagina HTML. Se il foglio completo è già piccolo, diciamo poche decine di kilobyte compressi, e viene servito con una buona cache, la complessità aggiuntiva spesso non vale il guadagno. Inoltre, se il CSS critico estratto non copre bene la parte visibile, all'arrivo del foglio completo si ha uno spostamento di layout che peggiora il CLS.

Dividere il CSS per pagina o per componente

Un'alternativa intermedia, spesso più semplice da mantenere, è suddividere il CSS: un file comune piccolo con le regole di base, e file separati per sezioni specifiche (negozio, blog, area riservata) caricati solo dove servono. Con HTTP/2 qualche file in più non è un problema, e ogni pagina scarica solo ciò che usa.

Altri sprechi da controllare

  • @import dentro il CSS: crea catene di download sequenziali. Meglio collegare i file direttamente nell'HTML o unirli in fase di build.
  • CSS per la stampa o per media query lontane: collegandolo con l'attributo media="print", il browser lo scarica con bassa priorità e senza bloccare il rendering.
  • Font e immagini base64 nel CSS: gonfiano il file bloccante con dati che potrebbero arrivare in parallelo.

In sintesi

  • Il CSS nell'intestazione blocca il rendering: meno ce n'è, prima si vede la pagina.
  • Il pannello Copertura mostra il CSS inutilizzato, ma va letto su più pagine e interazioni.
  • Elimina alla fonte o con strumenti di pulizia, proteggendo le classi dinamiche con una safelist.
  • Il CSS critico incorporato accelera il primo rendering, ma non sempre vale la complessità.
  • Evita @import, separa il CSS di stampa e dividi per sezione dove ha senso.
MM
Marco Marzaduri

Marco Marzaduri si occupa di cybersecurity, informatica forense e sviluppo web. Laureato in informatica, unisce il rigore dell'analisi tecnica all'attenzione per le persone che usano la tecnologia.

Leggi anche