Stagione 93 / Episodio 8
Esporre il mosaico
Servire WebP sul web nel 2026: quando basta un img, quando serve picture, negoziazione con Accept e Vary, nginx, CSS image-set, attributi per le prestazioni e i posti dove WebP non conviene ancora.
Note dell'episodio
Bentornati in bottega. Un mosaico non finisce quando l'ultima tessera è posata. Va portato fuori, appeso, illuminato. E va appeso in modo che chiunque passi lo veda bene: chi ha una buona vista e chi no, chi guarda da vicino e chi da lontano.
Per noi l'esposizione è la consegna al browser. Ed è un tema che nel corso degli anni è cambiato molto, perché per dieci anni il problema principale di WebP è stato: e se il browser non lo capisce?
Partiamo da una constatazione. Nel 2016, servire WebP significava gestire per forza un'alternativa: Safari e Firefox non lo leggevano. Oggi tutti i browser in uso lo supportano. Safari dalla versione 14 del 2020, Firefox dalla 65 del 2019, Edge e Chrome da molto prima.
Questo significa che, per un sito che si rivolge al pubblico generale, potete servire direttamente un file WebP in un elemento img, senza alternative. Quello che resta fuori sono browser molto vecchi e pochi ambienti particolari, e vale la pena chiedersi se il costo di mantenere doppie versioni di ogni immagine giustifica quel pubblico.
Detto questo, ci sono tre motivi per cui l'elemento picture con più sorgenti resta attuale. Il primo: volete offrire anche un formato più moderno, come AVIF o JPEG XL, con WebP come seconda scelta. Il secondo: il vostro pubblico include davvero dispositivi vecchi, per esempio un'applicazione aziendale su tablet mai aggiornati. Il terzo: il sito ha già un'infrastruttura così e non c'è motivo di toccarla.
Ricordiamo come funziona. Dentro un elemento picture mettete uno o più elementi source, ognuno con un attributo type, per esempio image slash webp, e un attributo srcset con i file. In fondo, un normale elemento img con il formato di riserva. Il browser scorre le sorgenti nell'ordine e prende la prima di cui capisce il tipo. Se non ne capisce nessuna, usa l'img.
L'ordine conta: il formato più efficiente va per primo. AVIF, poi WebP, poi JPEG nell'img finale. E gli attributi importanti, come alt, width, height, loading, vanno sull'img, non sulle sorgenti. L'elemento img è quello che viene davvero mostrato: le sorgenti gli suggeriscono solo quale file caricare.
Un vantaggio di picture è che la scelta avviene nel browser, con l'HTML. Non c'è bisogno di nessuna configurazione sul server e le cache funzionano senza sorprese, perché ogni URL corrisponde sempre allo stesso file.
L'alternativa è lasciare l'HTML com'è, con un solo URL per immagine, e far scegliere al server. Quando il browser chiede un'immagine, manda un'intestazione Accept con i formati che preferisce. I browser moderni ci mettono image slash webp, e spesso anche image slash avif. Il server legge l'intestazione e risponde con il formato migliore disponibile.
È comodo, soprattutto su siti esistenti con migliaia di immagini già referenziate nei contenuti. Ma ha un prezzo che non va sottovalutato: la cache.
Se lo stesso URL può restituire un JPEG a un browser e un WebP a un altro, qualunque cache intermedia deve saperlo. Altrimenti la CDN mette in cache il WebP chiesto da Chrome e lo consegna a un client che non lo capisce, oppure il contrario.
Per questo, quando negoziate il formato, la risposta deve contenere l'intestazione Vary con il valore Accept. È il cartellino accanto al mosaico che dice: attenzione, questa opera cambia a seconda di chi la guarda.
Il problema è che l'intestazione Accept non è uniforme. Ogni browser, e talvolta ogni versione, ne manda una leggermente diversa. Una cache che usa l'intestazione grezza come chiave finisce per conservare tante copie della stessa immagine. Le CDN serie normalizzano l'Accept in poche categorie, per esempio "supporta AVIF", "supporta WebP", "nessuno dei due". Se usate una CDN, verificate che lo faccia, altrimenti l'efficienza della cache crolla.
Vediamo l'approccio più diffuso con nginx. Per ogni immagine originale, mettiamo accanto una versione WebP con lo stesso nome e l'estensione aggiuntiva: foto punto jpg, e foto punto jpg punto webp.
Poi, nella configurazione, una direttiva map legge l'intestazione Accept e, se contiene image slash webp, imposta una variabile con il suffisso punto webp, altrimenti la lascia vuota. Nel blocco location per le immagini, try files prova prima il file con il suffisso, poi l'originale. E naturalmente si aggiunge Vary Accept alla risposta.
Il vantaggio di questo schema è che degrada bene: se per qualche immagine manca la versione WebP, nginx serve l'originale senza errori. Nelle note trovate la configurazione completa.
Due dettagli. Il primo: assicuratevi che il file dei tipi MIME di nginx associ l'estensione webp a image slash webp. Nelle versioni recenti c'è già, ma su server vecchi o configurazioni copiate da chissà dove a volte manca, e allora il file viene servito come binario generico. Il secondo: non comprimete con gzip o brotli le immagini WebP. Sono già compresse, e la seconda compressione spreca processore senza guadagnare byte.
Anche le immagini di sfondo nei CSS possono avere più formati. La funzione image-set permette di elencare più file, ognuno con il suo tipo, e il browser sceglie il primo che supporta. Si scrive con la funzione type e il media type tra virgolette. Come per picture, il formato migliore va per primo, e conviene sempre dichiarare prima un normale background-image di riserva per i browser che non conoscono image-set con i tipi.
Un'immagine leggera ma esposta male rovina comunque la pagina. Tre attributi da non dimenticare mai sull'elemento img.
Width e height, con le dimensioni intrinseche dell'immagine. Permettono al browser di riservare lo spazio prima di scaricarla, ed evitano che la pagina salti quando l'immagine arriva. È uno dei problemi che le metriche di Core Web Vitals misurano come spostamento cumulativo del layout.
Loading uguale lazy per le immagini sotto la piega: il browser le scarica solo quando l'utente si avvicina. Ma attenzione: mai sull'immagine principale in cima alla pagina, perché ritarderebbe proprio l'elemento che conta di più.
E per quell'immagine principale, quella che di solito determina la metrica del contenuto più grande visibile, l'attributo fetchpriority uguale high dice al browser di scaricarla per prima.
A questo aggiungete srcset e sizes per offrire più larghezze: un telefono non deve scaricare l'immagine larga duemila pixel pensata per un monitor grande. Il formato WebP riduce il peso di ogni versione, srcset riduce il numero di pixel inutili. Insieme fanno la vera differenza.
Infine, i posti dove lo appenderei con cautela.
Le email. Il supporto di WebP nei programmi di posta è molto più irregolare che nei browser, e alcuni client desktop molto diffusi non lo mostrano. Nelle newsletter, PNG e JPEG restano la scelta prudente.
Le immagini di anteprima per i social, quelle indicate nei metadati Open Graph. Molte piattaforme leggono WebP, ma non tutte e non sempre bene. Per l'immagine che appare quando qualcuno condivide un vostro articolo, un JPEG resta la scelta più sicura.
E i file che gli utenti scaricano per usarli altrove: una foto che qualcuno vuole stampare, aprire in un vecchio programma di grafica o allegare a un documento. Lì un WebP può creare più problemi di quanti ne risolva.
Ricapitolando: nel 2026 un img con un WebP funziona ovunque nei browser. Picture serve per offrire più formati o per pubblici con dispositivi vecchi. La negoziazione con Accept è comoda ma richiede Vary e una cache che normalizzi l'intestazione. Image-set fa lo stesso nei CSS. E le dimensioni, il caricamento differito e la priorità contano quanto il formato.
Nel prossimo episodio torniamo dietro il bancone e scriviamo codice: come si produce WebP in Go, PHP, Laravel, Node.js e Python, e come si costruisce una pipeline di conversione che non vi esploda in mano. Ci sentiamo lì.