Nel modulo precedente, è stata esaminata la teoria alla base del percorso di rendering critico e il modo in cui le risorse di blocco del rendering e di blocco dell'analisi possono ritardare il rendering iniziale di una pagina. Ora che hai compreso alcuni aspetti teorici, puoi imparare alcune tecniche per ottimizzare il percorso di rendering critico.
Quando una pagina viene caricata, nel codice HTML vengono citate molte risorse che forniscono alla pagina il suo aspetto e il suo layout tramite CSS, nonché la sua interattività tramite JavaScript. In questo modulo vengono trattati una serie di concetti importanti relativi a queste risorse e al modo in cui influiscono sul tempo di caricamento di una pagina.
Blocco del rendering
Come discusso nel modulo precedente, CSS è una risorsa che blocca il rendering, in quanto impedisce al browser di eseguire il rendering di qualsiasi contenuto finché non viene creato il CSS Object Model (CSSOM). Il browser blocca il rendering per evitare un Flash of Unstyled Content (FOUC), che è indesiderabile dal punto di vista dell'esperienza utente.
Nel video precedente, si verifica un breve FOUC in cui puoi vedere la pagina senza alcuno stile. Successivamente, tutti gli stili vengono applicati una volta terminato il caricamento del CSS della pagina dalla rete e la versione senza stile della pagina viene immediatamente sostituita con la versione con stile.
In generale, un FOUC è qualcosa che non si vede normalmente, ma il concetto è importante da capire per sapere perché il browser blocca il rendering della pagina finché il CSS non viene scaricato e applicato alla pagina. Il blocco del rendering non è necessariamente indesiderabile, ma devi ridurre al minimo la sua durata mantenendo ottimizzato il CSS.
Blocco del parser
Una risorsa che blocca l'analisi interrompe l'analizzatore HTML, ad esempio un elemento <script>
senza attributi async
o defer
. Quando il parser rileva un elemento
<script>
, il browser deve valutare ed eseguire lo script prima di
procedere con l'analisi del resto dell'HTML. Ciò avviene intenzionalmente, in quanto gli script potrebbero
modificare o accedere al DOM durante la sua costruzione.
<!-- This is a parser-blocking script: -->
<script src="/script.js"></script>
Quando si utilizzano file JavaScript esterni (senza async
o defer
), il parser viene
bloccato dal momento in cui il file viene rilevato fino a quando non viene scaricato, analizzato ed
eseguito. Quando si utilizza JavaScript incorporato, il parser viene bloccato in modo simile finché
lo script incorporato non viene analizzato ed eseguito.
Lo scanner di precaricamento
Lo scanner di precaricamento è un'ottimizzazione del browser sotto forma di parser HTML secondario che analizza la risposta HTML non elaborata per trovare e recuperare in modo speculativo le risorse prima che il parser HTML principale le rilevi. Ad esempio, lo scanner di precaricamento consentirebbe al browser di iniziare a scaricare una risorsa specificata in un elemento <img>
, anche quando il parser HTML è bloccato durante il recupero e l'elaborazione di risorse come CSS e JavaScript.
Per sfruttare lo scanner di precaricamento, le risorse critiche devono essere incluse nel markup HTML inviato dal server. I seguenti pattern di caricamento delle risorse non sono rilevabili dallo scanner di precaricamento:
- Immagini caricate da CSS utilizzando la proprietà
background-image
. Questi riferimenti alle immagini sono in CSS e non possono essere rilevati dallo scanner di precaricamento. - Script caricati dinamicamente sotto forma di markup dell'elemento
<script>
inserito nel DOM utilizzando JavaScript o moduli caricati utilizzandoimport()
dinamico. - HTML sottoposto a rendering sul client utilizzando JavaScript. Questo markup è contenuto all'interno di stringhe nelle risorse JavaScript e non è rilevabile dallo scanner di precaricamento.
- Dichiarazioni CSS
@import
.
Questi pattern di caricamento delle risorse sono tutte risorse rilevate in un secondo momento e pertanto
non traggono vantaggio dallo scanner di precaricamento. Evitali quando possibile. Se
evitare questi pattern non è possibile, puoi utilizzare un
suggerimento preload
per evitare ritardi nel rilevamento delle risorse.
CSS
Il CSS determina la presentazione e il layout di una pagina. Come descritto in precedenza, il CSS è una risorsa che blocca il rendering, pertanto l'ottimizzazione del CSS potrebbe avere un impatto notevole sul tempo di caricamento complessivo della pagina.
Minimizzazione
La minimizzazione dei file CSS riduce le dimensioni di un file CSS, rendendone più rapido il download. Ciò si ottiene principalmente rimuovendo i contenuti da un file CSS di origine, ad esempio spazi e altri caratteri invisibili, e restituendo il risultato in un file appena ottimizzato:
/* Unminified CSS: */
/* Heading 1 */
h1 {
font-size: 2em;
color: #000000;
}
/* Heading 2 */
h2 {
font-size: 1.5em;
color: #000000;
}
/* Minified CSS: */
h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}
Nella sua forma più semplice, la minimizzazione del CSS è un'ottimizzazione efficace che potrebbe migliorare l'FCP del tuo sito web e, in alcuni casi, anche l'LCP. Strumenti come i bundler possono eseguire automaticamente questa ottimizzazione per te nelle build di produzione.
Rimuovi il CSS inutilizzato
Prima di eseguire il rendering di qualsiasi contenuto, il browser deve scaricare e analizzare tutti i fogli di stile. Il tempo necessario per completare l'analisi include anche gli stili non utilizzati nella pagina corrente. Se utilizzi un bundler che combina tutte le risorse CSS in un unico file, è probabile che i tuoi utenti scarichino più CSS del necessario per il rendering della pagina corrente.
Per scoprire i CSS inutilizzati per la pagina corrente, utilizza lo strumento Copertura in Chrome DevTools.

La rimozione del CSS inutilizzato ha un duplice effetto: oltre a ridurre il tempo di download, ottimizzi la costruzione dell'albero di rendering, poiché il browser deve elaborare meno regole CSS.
Evita le dichiarazioni CSS @import
Sebbene possa sembrare conveniente, devi evitare le dichiarazioni @import
nel CSS:
/* Don't do this: */
@import url('style.css');
Analogamente al funzionamento dell'elemento <link>
in HTML, la dichiarazione @import
in CSS consente di importare una risorsa CSS esterna da un foglio di stile. La
differenza principale tra questi due approcci è che l'elemento HTML <link>
fa parte della risposta HTML e viene quindi rilevato molto prima di un file CSS
scaricato da una dichiarazione @import
.
Il motivo è che, affinché una dichiarazione @import
venga
rilevata, è necessario prima scaricare il file CSS che la contiene. Ciò
genera quella che è nota come catena di richieste che, nel caso dei CSS, ritarda
il tempo necessario per il rendering iniziale di una pagina. Un altro svantaggio è che i fogli di stile caricati utilizzando una dichiarazione @import
non possono essere rilevati dallo scanner di precaricamento e diventano quindi risorse di blocco del rendering rilevate in ritardo.
<!-- Do this instead: -->
<link rel="stylesheet" href="style.css">
Nella maggior parte dei casi, puoi sostituire @import
utilizzando un elemento
<link rel="stylesheet">
. Gli elementi <link>
consentono di scaricare i fogli di stile contemporaneamente e riducono il tempo di caricamento complessivo, a differenza delle dichiarazioni @import
, che scaricano i fogli di stile in sequenza.
CSS critico incorporato
Il tempo necessario per scaricare i file CSS può aumentare l'FCP di una pagina. L'incorporamento
degli stili critici nel documento <head>
elimina la richiesta di rete per una
risorsa CSS e, se eseguito correttamente, può migliorare i tempi di caricamento iniziali quando la
cache del browser di un utente non è preparata. Il CSS rimanente può essere caricato
in modo asincrono o aggiunto alla fine dell'elemento <body>
.
<head>
<title>Page Title</title>
<!-- ... -->
<style>h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}</style>
</head>
<body>
<!-- Other page markup... -->
<link rel="stylesheet" href="non-critical.css">
</body>
Lo svantaggio è che l'incorporamento di una grande quantità di CSS aggiunge più byte alla risposta HTML iniziale. Poiché le risorse HTML spesso non possono essere memorizzate nella cache per molto tempo o per niente, ciò significa che il CSS incorporato non viene memorizzato nella cache per le pagine successive che potrebbero utilizzare lo stesso CSS in fogli di stile esterni. Testa e misura le prestazioni della tua pagina per assicurarti che i compromessi valgano la pena.
Demo CSS
JavaScript
JavaScript è alla base della maggior parte dell'interattività sul web, ma ha un costo. L'invio di troppo JavaScript può rallentare la risposta della pagina web durante il caricamento della pagina e può persino causare problemi di reattività che rallentano le interazioni, il che può essere frustrante per gli utenti.
JavaScript di blocco del rendering
Quando carichi elementi <script>
senza gli attributi defer
o async
, il browser blocca l'analisi e il rendering finché lo script non viene scaricato, analizzato ed eseguito. Allo stesso modo, gli script incorporati bloccano il parser finché lo script non viene analizzato
ed eseguito.
async
contro defer
async
e defer
consentono il caricamento di script esterni senza bloccare il parser HTML, mentre gli script (inclusi quelli incorporati) con type="module"
vengono posticipati automaticamente. Tuttavia, async
e defer
presentano alcune differenze importanti da comprendere.
Gli script caricati con async
vengono analizzati ed eseguiti immediatamente dopo il download,
mentre gli script caricati con defer
vengono eseguiti al termine dell'analisi del documento HTML, ovvero contemporaneamente all'evento DOMContentLoaded
del browser.
Inoltre, gli script async
potrebbero essere eseguiti in ordine sparso, mentre gli script defer
vengono eseguiti nell'ordine in cui appaiono nel markup.
Rendering lato client
In generale, dovresti evitare di utilizzare JavaScript per il rendering di contenuti critici o dell'elemento LCP di una pagina. Questa tecnica è nota come rendering lato client e viene utilizzata in modo esteso nelle applicazioni a pagina singola (SPA).
Il markup sottoposto a rendering da JavaScript aggira lo scanner di precaricamento, in quanto le risorse contenute nel markup sottoposto a rendering lato client non sono rilevabili. Ciò potrebbe ritardare il download di risorse cruciali, come un'immagine LCP. Il browser inizia a scaricare l'immagine LCP solo dopo l'esecuzione dello script e l'aggiunta dell'elemento al DOM. A sua volta, lo script può essere eseguito solo dopo essere stato individuato, scaricato e analizzato. Questo è noto come catena di richieste critiche e deve essere evitato.
Inoltre, il rendering del markup utilizzando JavaScript ha maggiori probabilità di generare attività lunghe rispetto al markup scaricato dal server in risposta a una richiesta di navigazione. L'utilizzo esteso del rendering lato client dell'HTML può influire negativamente sulla latenza di interazione. Ciò è particolarmente vero nei casi in cui il DOM di una pagina è molto grande, il che attiva un lavoro di rendering significativo quando JavaScript modifica il DOM.
Minimizzazione
Come per CSS, la minimizzazione di JavaScript riduce le dimensioni del file di una risorsa di script. Ciò può portare a download più rapidi, consentendo al browser di passare più rapidamente all'analisi e alla compilazione di JavaScript.
Inoltre, la minimizzazione di JavaScript va oltre la minimizzazione di altri asset, come i CSS. Quando JavaScript viene compresso, non vengono rimossi solo spazi, tabulazioni e commenti, ma anche i simboli nel codice JavaScript di origine vengono abbreviati. Questo processo è talvolta noto come uglification. Per vedere la differenza, prendi il seguente codice sorgente JavaScript:
// Unuglified JavaScript source code:
export function injectScript () {
const scriptElement = document.createElement('script');
scriptElement.src = '/js/scripts.js';
scriptElement.type = 'module';
document.body.appendChild(scriptElement);
}
Quando il codice sorgente JavaScript precedente viene compresso, il risultato potrebbe avere un aspetto simile al seguente snippet di codice:
// Uglified JavaScript production code:
export function injectScript(){const t=document.createElement("script");t.src="/js/scripts.js",t.type="module",document.body.appendChild(t)}
Nello snippet precedente, puoi notare che la variabile leggibile
scriptElement
nell'origine è abbreviata in t
. Se applicati a una vasta raccolta di script, i risparmi possono essere piuttosto significativi, senza influire sulle funzionalità fornite dal codice JavaScript di produzione di un sito web.
Se utilizzi un bundler per elaborare il codice sorgente del tuo sito web, l'offuscamento viene spesso eseguito automaticamente per le build di produzione. Anche gli uglifier, come Terser, ad esempio, sono altamente configurabili, il che ti consente di modificare l'aggressività dell'algoritmo di uglification per ottenere il massimo risparmio. Tuttavia, i valori predefiniti di qualsiasi strumento di offuscamento sono in genere sufficienti per trovare il giusto equilibrio tra le dimensioni dell'output e la conservazione delle funzionalità.
Demo JavaScript
Verifica le tue conoscenze
Qual è il modo migliore per caricare più file CSS nel browser?
@import
.<link>
.Che cosa fa lo scanner di precaricamento del browser?
<link rel="preload">
in
una risorsa HTML.
Perché il browser blocca temporaneamente l'analisi dell'HTML per impostazione predefinita durante il download delle risorse JavaScript?
Passaggio successivo: aiutare il browser con i suggerimenti per le risorse
Ora che hai capito come le risorse caricate nell'elemento <head>
possono influire sul caricamento iniziale della pagina e su varie metriche, è il momento di andare avanti. Nel modulo successivo, vengono esplorate le indicazioni sulle risorse e come possono fornire suggerimenti preziosi al browser per iniziare a caricare le risorse e aprire connessioni a server cross-origin prima di quanto farebbe altrimenti senza.