Preload, preconnect e fetchpriority: come dire al browser cosa conta davvero

dns-prefetch, preconnect, preload, prefetch e fetchpriority: come il browser decide le priorità, quando ogni suggerimento accelera la pagina e quando la rallenta, con esempi per WordPress.

Un browser che riceve risorse da una coda di richieste, con l’immagine hero in verde che passa davanti alle altre con priorità alta

Un browser che carica una pagina deve prendere continuamente decisioni: quale risorsa scaricare per prima, quale può aspettare, con quali server aprire una connessione. Lo fa con euristiche sofisticate, basate sul tipo di risorsa e sulla sua posizione nel documento, ma non conosce la pagina come chi l’ha costruita. Non sa che quell’immagine è la più importante, che quel font serve già al primo disegno, che quel dominio di terze parti verrà contattato tra un istante.

I resource hints e l’attributo fetchpriority servono a colmare questa distanza: sono il modo in cui lo sviluppatore può dire al browser cosa conta davvero. Usati bene, anticipano le risorse critiche e fanno guadagnare centinaia di millisecondi sull’LCP. Usati male, e succede spesso, fanno competere risorse inutili con quelle importanti e rallentano proprio ciò che volevano accelerare. In questo articolo li vediamo uno per uno, con i casi in cui servono e quelli in cui fanno danni.

Come il browser decide le priorità

Per capire quando un suggerimento serve, bisogna sapere cosa fa il browser senza. Mentre legge l’HTML, un componente chiamato preload scanner scorre il documento in anticipo e individua le risorse da scaricare: fogli di stile, script, immagini. Ciascuna riceve una priorità in base al tipo: i fogli di stile nell’intestazione hanno priorità massima, perché bloccano il rendering; gli script sincroni alta; i font alta, ma vengono scoperti solo quando il CSS li richiede; le immagini, per impostazione predefinita, bassa.

Le immagini sono il caso più delicato. Il browser non sa quali saranno visibili finché non ha calcolato il layout, e fino a quel momento le tratta con priorità bassa, con qualche eccezione per le prime immagini grandi del documento nelle versioni recenti di Chrome. Solo dopo il layout, quando scopre che un’immagine è nello schermo iniziale, ne alza la priorità. Per l’immagine principale di una pagina, che è quasi sempre l’elemento LCP, questo significa partire in ritardo e in coda ad altre risorse.

Ci sono poi risorse che il preload scanner non vede affatto: font dichiarati nel CSS, immagini di sfondo definite nei fogli di stile, script inseriti da altri script, risorse richieste da JavaScript. Il browser le scopre solo quando arriva al punto in cui vengono usate, spesso diverse centinaia di millisecondi dopo l’inizio del caricamento.

Tabella dei cinque suggerimenti: dns-prefetch risolve il nome del dominio, per domini terzi usati più avanti, costo minimo; preconnect apre in anticipo DNS, TCP e TLS, per due-quattro domini critici, costo basso; preload scarica subito una risorsa, per font, immagini hero nel CSS e risorse scoperte tardi, costo alto se sbagliato; fetchpriority cambia la priorità di una richiesta, per l’immagine LCP e le immagini secondarie, nessun costo; prefetch scarica per la pagina successiva, per navigazioni molto probabili, rischio di banda sprecata
Ogni suggerimento anticipa un lavoro diverso del browser.

dns-prefetch e preconnect: preparare la strada

Prima di scaricare una risorsa da un dominio nuovo, il browser deve risolverne il nome tramite DNS, aprire una connessione TCP e negoziare la cifratura TLS. Su una rete mobile questi passaggi possono richiedere da 100 a 300 millisecondi, e si ripetono per ogni dominio diverso: la CDN delle immagini, il servizio dei font, la piattaforma di analytics, il sistema di pagamento.

preconnect chiede al browser di completare tutti questi passaggi subito, in modo che la connessione sia pronta quando la risorsa verrà richiesta. dns-prefetch fa solo la prima parte, la risoluzione del nome: costa meno e si può usare per più domini.

<!-- Connessione completa: per i domini critici del primo disegno -->
<link rel="preconnect" href="https://cdn.esempio.it">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

<!-- Solo DNS: per domini usati più avanti -->
<link rel="dns-prefetch" href="https://www.googletagmanager.com">

Il preconnect ha senso per pochi domini, due o quattro, da cui arrivano risorse necessarie al primo disegno: il dominio delle immagini se diverso da quello del sito, il servizio dei font, una CDN di risorse statiche. Aprire connessioni in anticipo verso dieci domini ha l’effetto opposto: il browser e il dispositivo lavorano per connessioni che magari verranno usate dopo diversi secondi, o mai, e che nel frattempo possono essere chiuse per inattività. L’attributo crossorigin è importante: i font vengono richiesti in modalità CORS, che usa una connessione separata, e un preconnect senza crossorigin verso il dominio dei font prepara la connessione sbagliata.

Il modo migliore di risparmiare questi passaggi, però, è non averne bisogno: ospitare font e risorse statiche sullo stesso dominio del sito, come abbiamo visto parlando del subsetting dei font, elimina del tutto le connessioni aggiuntive.

preload: scaricare subito ciò che verrebbe scoperto tardi

preload chiede al browser di scaricare una risorsa specifica immediatamente, con alta priorità, anche se non l’ha ancora incontrata nel documento. È lo strumento per le risorse che il preload scanner non vede e che servono presto: il font principale dichiarato nel CSS, l’immagine hero impostata come sfondo in un foglio di stile, lo script caricato dinamicamente da un altro script ma indispensabile al primo disegno.

<!-- Font usato nel testo sopra la piega -->
<link rel="preload" href="/fonts/plex-400.woff2" as="font" type="font/woff2" crossorigin>

<!-- Immagine hero definita come sfondo CSS, con varianti responsive -->
<link rel="preload" as="image" href="/media/hero-1600.webp"
	imagesrcset="/media/hero-800.webp 800w, /media/hero-1600.webp 1600w"
	imagesizes="100vw" fetchpriority="high">

Alcuni dettagli fanno la differenza tra un preload utile e uno dannoso. L’attributo as è obbligatorio: indica il tipo di risorsa, determina la priorità e permette al browser di riutilizzare la risorsa scaricata quando la incontra nel documento. Per i font serve crossorigin, anche sullo stesso dominio, altrimenti il browser scarica il font due volte. Per le immagini responsive, imagesrcset e imagesizes fanno scegliere al browser la stessa variante che sceglierà l’elemento immagine; un preload di una sola dimensione rischia di scaricare un file che poi non verrà usato.

Il preload non va usato per risorse che il browser trova già da solo in tempo. Un’immagine normale nell’HTML, con src e fetchpriority, non ha bisogno di preload: il preload scanner la trova subito. Un foglio di stile nell’intestazione nemmeno. Il preload serve dove c’è una scoperta tardiva da eliminare, non come modo generico per dire «questo è importante».

Il problema dell’eccesso

Il preload è anche lo strumento più abusato. Plugin di ottimizzazione, temi e configurazioni copiate da altri progetti finiscono spesso per precaricare decine di risorse: tutti i font in tutte le varianti, script, fogli di stile secondari, immagini che non sono sopra la piega. Poiché ogni preload riceve alta priorità, il risultato è una competizione in cui nulla è davvero prioritario: il foglio di stile principale e l’immagine LCP si dividono la banda con risorse che servono dopo o non servono affatto. Chrome segnala nella console le risorse precaricate e non utilizzate entro pochi secondi: è il primo controllo da fare su un sito con molti preload.

fetchpriority: cambiare la priorità senza anticipare

L’attributo fetchpriority è il più recente e, per l’LCP, spesso il più efficace. Non anticipa la scoperta di una risorsa: ne cambia la priorità quando viene scoperta. Può valere high, low o auto, e si applica a immagini, script, fogli di stile, iframe e preload. È supportato da tutti i browser principali nelle versioni recenti; chi non lo supporta lo ignora.

Il caso d’uso principale è l’immagine LCP. Con fetchpriority="high", il browser la scarica con alta priorità fin dall’inizio, invece di aspettare il layout per scoprire che è visibile. Il guadagno può essere di diverse centinaia di millisecondi, con una sola parola aggiunta al markup, come spiegato nell’articolo sull’LCP.

Tre caricamenti a confronto: con la priorità predefinita l’immagine hero parte bassa e sale solo dopo il layout, LCP 2,3 secondi; con fetchpriority high parte subito ad alta priorità, LCP 1,4 secondi; con otto preload tutti insieme le risorse competono, il CSS rallenta e l’LCP sale a 2,6 secondi
La priorità giusta anticipa ciò che conta; l’eccesso di preload rallenta tutto.
<!-- L’immagine principale: priorità alta, nessun lazy loading -->
<img src="/media/copertina.webp" width="1200" height="630"
	fetchpriority="high" alt="…">

<!-- Le diapositive nascoste di un carosello: priorità bassa -->
<img src="/media/slide-2.webp" width="1200" height="630"
	fetchpriority="low" alt="…">

<!-- Uno script non critico: priorità bassa -->
<script src="/js/widget.js" async fetchpriority="low"></script>

Il valore low è utile quanto high, e molto meno usato. Le immagini di un carosello che non sono visibili all’inizio, un’immagine grande ma secondaria sopra la piega, uno script asincrono che non serve al primo disegno: abbassarne la priorità lascia più banda alle risorse che contano. Anche le richieste fatte con fetch() accettano un’opzione di priorità, utile per distinguere i dati necessari subito da quelli che possono aspettare.

Anche qui vale la regola della parsimonia: fetchpriority="high" su un’immagine per pagina, quella LCP, al massimo due. Assegnarlo a tutte le immagini visibili equivale a non assegnarlo a nessuna. E non va mai combinato con loading="lazy", che rimanda il caricamento a dopo il layout annullando l’effetto, come abbiamo visto nell’articolo sul lazy loading.

prefetch e modulepreload

prefetch chiede al browser di scaricare, con priorità molto bassa e quando è inattivo, una risorsa che servirà probabilmente nella pagina successiva. È stato a lungo l’unico modo di anticipare le navigazioni; oggi, per le pagine intere, le Speculation Rules offrono un controllo molto migliore, con prefetch e prerender guidati dal comportamento dell’utente. Il prefetch di singole risorse resta utile in casi specifici, come il foglio di stile della pagina di checkout precaricato dal carrello.

modulepreload è la versione del preload per i moduli JavaScript: scarica e analizza in anticipo un modulo e, a seconda del browser, le sue dipendenze. È utile nelle applicazioni che usano moduli nativi, dove la catena delle importazioni viene altrimenti scoperta un passaggio alla volta.

Suggerimenti nelle intestazioni HTTP

Preload e preconnect possono essere inviati anche come intestazioni HTTP Link, invece che come elementi nell’HTML. Il vantaggio è che il browser li riceve con le intestazioni, prima ancora di leggere il documento, e che possono essere gestiti dal server o dalla CDN senza modificare i template. Sono anche la base degli Early Hints, con cui il server comunica gli stessi suggerimenti mentre la pagina è ancora in preparazione.

Link: <https://cdn.esempio.it>; rel=preconnect
Link: </fonts/plex-400.woff2>; rel=preload; as=font; type="font/woff2"; crossorigin

Il caso WordPress

WordPress gestisce già alcuni di questi suggerimenti. Dalla versione 6.3 aggiunge automaticamente fetchpriority="high" all’immagine che stima essere l’elemento LCP e non applica il lazy loading alle prime immagini. Per i preconnect e i dns-prefetch esiste il filtro wp_resource_hints, e per i preload il filtro wp_preload_resources, disponibile dalla versione 6.1:

// Preconnect verso la CDN delle immagini
add_filter(
	'wp_resource_hints',
	function ( $urls, $tipo ) {
		if ( 'preconnect' === $tipo ) {
			$urls[] = 'https://cdn.esempio.it';
		}
		return $urls;
	},
	10,
	2
);

// Preload del font principale del tema
add_filter(
	'wp_preload_resources',
	function ( $risorse ) {
		$risorse[] = array(
			'href'        => get_theme_file_uri( 'fonts/plex-400.woff2' ),
			'as'          => 'font',
			'type'        => 'font/woff2',
			'crossorigin' => true,
		);
		return $risorse;
	}
);

La stima automatica dell’immagine LCP funziona bene con i temi che usano le funzioni standard per le immagini, ma può sbagliare con costruttori di pagine, slider e blocchi personalizzati. E molti plugin di ottimizzazione aggiungono i propri preload e preconnect, a volte sovrapponendosi a quelli del tema o del core. Il risultato va quindi sempre verificato nel codice sorgente della pagina reale.

Come verificare

Nel pannello Network dei DevTools si può aggiungere la colonna Priority, che mostra la priorità di ogni richiesta e, con le impostazioni avanzate, anche quella iniziale. È il modo più diretto per vedere se l’immagine LCP parte con priorità alta e quando viene richiesta rispetto alle altre risorse. La console segnala i preload non utilizzati e i preconnect non usati. PageSpeed Insights, nella diagnosi dell’LCP, indica se l’immagine è stata scoperta tardi e se avrebbe beneficiato di fetchpriority o di un preload, e mostra quali domini meriterebbero un preconnect.

Un buon esercizio è confrontare il grafico a cascata prima e dopo ogni modifica: un suggerimento efficace sposta visibilmente a sinistra la risorsa a cui si applica senza spostare a destra quelle critiche. Se il foglio di stile principale o l’immagine LCP partono più tardi di prima, qualche suggerimento sta sottraendo loro banda.

Una regola per ricordarli

  • fetchpriority quando il browser trova la risorsa in tempo ma non sa che è importante.
  • preload quando la risorsa è importante ma il browser la troverebbe tardi.
  • preconnect quando la risorsa arriva da un altro dominio e serve presto.
  • dns-prefetch quando il dominio servirà più avanti e non vale una connessione completa.
  • prefetch o Speculation Rules quando la risorsa serve alla pagina successiva.

In sintesi

Resource hints e fetchpriority permettono di trasmettere al browser la conoscenza che ha solo chi ha costruito la pagina: quale risorsa conta di più, quale arriverà da un altro dominio, quale verrebbe scoperta troppo tardi. Per l’LCP, l’intervento più efficace è quasi sempre fetchpriority="high" sull’immagine principale; il preload serve per font e risorse nascoste nel CSS o nel JavaScript; il preconnect per pochi domini critici.

Sono strumenti potenti proprio perché cambiano l’ordine in cui il browser lavora, e per la stessa ragione vanno usati con parsimonia. Ogni suggerimento superfluo sottrae risorse a quelli utili. La regola pratica è semplice: pochi suggerimenti, mirati, verificati nel grafico a cascata prima e dopo.

IL PROSSIMO PASSO

Partiamo
dal tuo sito.

Raccontaci il progetto, i problemi che riscontri e i tuoi obiettivi. Definiremo insieme un intervento su misura.

Richiedi un’analisi

Ti porta al modulo della pagina Contatti.

MANAGED SERVER S.R.L.info@corewebvitals.it +39 02 5656 9681

Lunedì – venerdì · 09:30 – 19:30

Preferisci un modulo online?
Contattaci su managedserver.it ↗