Performance front-end 2021: ottimizzazioni degli asset
Pubblicato: 2022-03-10Questa guida è stata gentilmente supportata dai nostri amici di LogRocket, un servizio che combina il monitoraggio delle prestazioni del frontend , la riproduzione delle sessioni e l'analisi dei prodotti per aiutarti a creare esperienze migliori per i clienti. LogRocket tiene traccia delle metriche chiave, incl. DOM completo, tempo al primo byte, primo ritardo di input, CPU client e utilizzo della memoria. Ottieni una prova gratuita di LogRocket oggi.
Sommario
- Prepararsi: pianificazione e metriche
- Stabilire obiettivi realistici
- Definire l'ambiente
- Ottimizzazioni degli asset
- Costruisci ottimizzazioni
- Ottimizzazioni di consegna
- Rete, HTTP/2, HTTP/3
- Test e monitoraggio
- Vittorie veloci
- Tutto in una pagina
- Scarica la lista di controllo (PDF, Apple Pages, MS Word)
- Iscriviti alla nostra newsletter via email per non perdere le prossime guide.
Ottimizzazioni degli asset
- Usa Brotli per la compressione del testo normale.
Nel 2015, Google ha introdotto Brotli, un nuovo formato di dati senza perdita di dati open source, che ora è supportato in tutti i browser moderni. La libreria Brotli open source, che implementa un codificatore e un decoder per Brotli, ha 11 livelli di qualità predefiniti per l'encoder, con un livello di qualità superiore che richiede più CPU in cambio di un migliore rapporto di compressione. Una compressione più lenta alla fine porterà a tassi di compressione più elevati, tuttavia Brotli si decomprime rapidamente. Vale la pena notare però che Brotli con il livello di compressione 4 è più piccolo e si comprime più velocemente di Gzip.In pratica, Brotli sembra essere molto più efficace di Gzip. Le opinioni e le esperienze differiscono, ma se il tuo sito è già ottimizzato con Gzip, potresti aspettarti miglioramenti almeno a una cifra e nella migliore delle ipotesi miglioramenti a due cifre nella riduzione delle dimensioni e nei tempi FCP. Puoi anche stimare i risparmi di compressione Brotli per il tuo sito.
I browser accetteranno Brotli solo se l'utente sta visitando un sito Web tramite HTTPS. Brotli è ampiamente supportato e molti CDN lo supportano (Akamai, Netlify Edge, AWS, KeyCDN, Fastly (attualmente solo come pass-through), Cloudflare, CDN77) e puoi abilitare Brotli anche su CDN che non lo supportano ancora (con un addetto ai servizi).
Il problema è che, poiché la compressione di tutte le risorse con Brotli a un livello di compressione elevato è costosa, molti provider di hosting non possono utilizzarlo su vasta scala solo a causa dell'enorme sovraccarico di costi che produce. Infatti, al più alto livello di compressione, Brotli è così lento che qualsiasi potenziale aumento delle dimensioni del file potrebbe essere annullato dal tempo impiegato dal server per iniziare a inviare la risposta mentre attende di comprimere dinamicamente l'asset. (Ma se hai tempo durante il tempo di costruzione con la compressione statica, ovviamente, sono preferibili impostazioni di compressione più elevate.)
Questo potrebbe cambiare però. Il formato di file Brotli include un dizionario statico integrato e, oltre a contenere varie stringhe in più lingue, supporta anche l'opzione di applicare più trasformazioni a quelle parole, aumentandone la versatilità. Nella sua ricerca, Felix Hanau ha scoperto un modo per migliorare la compressione ai livelli da 5 a 9 utilizzando "un sottoinsieme del dizionario più specializzato rispetto a quello predefinito" e basandosi sull'intestazione
Content-Type
per dire al compressore se deve utilizzare un dizionario per HTML, JavaScript o CSS. Il risultato è stato un "impatto trascurabile sulle prestazioni (dall'1% al 3% in più di CPU rispetto al 12% normalmente) durante la compressione di contenuti Web a livelli di compressione elevati, utilizzando un approccio di utilizzo limitato del dizionario".Inoltre, con la ricerca di Elena Kirilenko, possiamo ottenere una ricompressione Brotli rapida ed efficiente utilizzando precedenti artefatti di compressione. Secondo Elena, "una volta che abbiamo una risorsa compressa tramite Brotli, e stiamo cercando di comprimere il contenuto dinamico al volo, in cui il contenuto assomiglia a quello a nostra disposizione in anticipo, possiamo ottenere miglioramenti significativi nei tempi di compressione. "
Quante volte è il caso? Ad esempio con la consegna di sottoinsiemi di bundle JavaScript (ad esempio quando parti del codice sono già memorizzate nella cache del client o con bundle dinamici che servono con WebBundles). Oppure con HTML dinamico basato su modelli noti in anticipo o caratteri WOFF2 con sottoinsiemi dinamici . Secondo Elena, possiamo ottenere un miglioramento del 5,3% sulla compressione e del 39% sulla velocità di compressione rimuovendo il 10% del contenuto e tassi di compressione migliori del 3,2% e una compressione più veloce del 26% rimuovendo il 50% del contenuto.
La compressione Brotli sta migliorando, quindi se riesci a bypassare il costo della compressione dinamica delle risorse statiche, ne vale sicuramente la pena. Inutile dire che Brotli può essere utilizzato per qualsiasi payload in testo normale: HTML, CSS, SVG, JavaScript, JSON e così via.
Nota : all'inizio del 2021, circa il 60% delle risposte HTTP viene fornito senza compressione basata su testo, con il 30,82% di compressione con Gzip e il 9,1% di compressione con Brotli (sia su dispositivi mobili che desktop). Ad esempio, il 23,4% delle pagine Angular non viene compresso (tramite gzip o Brotli). Tuttavia, spesso attivare la compressione è una delle vittorie più facili per migliorare le prestazioni con un semplice tocco di un interruttore.
La strategia? Precomprime le risorse statiche con Brotli+Gzip al livello più alto e comprimi l'HTML (dinamico) al volo con Brotli al livello 4–6. Assicurati che il server gestisca correttamente la negoziazione dei contenuti per Brotli o Gzip.
- Utilizziamo il caricamento adattivo dei media e i suggerimenti dei client?
Proviene dalla terra delle vecchie notizie, ma è sempre un buon promemoria per utilizzare immagini reattive consrcset
,sizes
e l'elemento<picture>
. Soprattutto per i siti con un elevato ingombro multimediale, possiamo fare un ulteriore passo avanti con il caricamento adattivo dei media (in questo esempio React + Next.js), offrendo un'esperienza leggera a reti lente e dispositivi con memoria insufficiente e un'esperienza completa su reti veloci e -dispositivi di memoria. Nel contesto di React, possiamo ottenerlo con suggerimenti client sul server e hook adattivi di reazione sul client.Il futuro delle immagini reattive potrebbe cambiare radicalmente con l'adozione più ampia dei suggerimenti dei clienti. I suggerimenti del client sono campi di intestazione della richiesta HTTP, ad esempio
DPR
,Viewport-Width
,Width
,Save-Data
,Accept
(per specificare le preferenze del formato immagine) e altri. Dovrebbero informare il server sulle specifiche del browser, dello schermo, della connessione dell'utente, ecc.Di conseguenza, il server può decidere come riempire il layout con immagini di dimensioni adeguate e servire solo queste immagini nei formati desiderati. Con i suggerimenti per il client, spostiamo la selezione delle risorse dal markup HTML e nella negoziazione richiesta-risposta tra il client e il server.
Come Ilya Grigorik ha notato tempo fa, i suggerimenti dei clienti completano il quadro: non sono un'alternativa alle immagini reattive. "L'elemento
<picture>
fornisce il necessario controllo della direzione artistica nel markup HTML. I suggerimenti del client forniscono annotazioni sulle richieste di immagini risultanti che consentono l'automazione della selezione delle risorse. Service Worker fornisce funzionalità complete di gestione delle richieste e delle risposte sul client".Un addetto al servizio potrebbe, ad esempio, aggiungere nuovi valori di intestazione dei suggerimenti client alla richiesta, riscrivere l'URL e indirizzare la richiesta di immagine a una CDN, adattare la risposta in base alla connettività e alle preferenze dell'utente, ecc. Vale non solo per le risorse immagine, ma praticamente anche per tutte le altre richieste.
Per i client che supportano i suggerimenti client, è possibile misurare un risparmio del 42% di byte sulle immagini e oltre 1 MB di byte in meno per il 70° percentile. Su Smashing Magazine, potremmo anche misurare un miglioramento del 19-32%. I suggerimenti per i client sono supportati nei browser basati su Chromium, ma sono ancora presi in considerazione in Firefox.
Tuttavia, se fornisci sia il normale markup delle immagini reattive che il tag
<meta>
per i suggerimenti client, un browser di supporto valuterà il markup delle immagini reattive e richiederà l'origine dell'immagine appropriata utilizzando le intestazioni HTTP dei suggerimenti client. - Usiamo immagini reattive per le immagini di sfondo?
Dovremmo sicuramente! Conimage-set
, ora supportato in Safari 14 e nella maggior parte dei browser moderni ad eccezione di Firefox, possiamo offrire anche immagini di sfondo reattive:background-image: url("fallback.jpg"); background-image: image-set( "photo-small.jpg" 1x, "photo-large.jpg" 2x, "photo-print.jpg" 600dpi);
Fondamentalmente possiamo servire in modo condizionale immagini di sfondo a bassa risoluzione con un descrittore
1x
e immagini ad alta risoluzione con descrittore2x
e persino un'immagine di qualità di stampa con descrittore600dpi
. Attenzione però: i browser non forniscono alcuna informazione speciale sulle immagini di sfondo alla tecnologia assistiva, quindi idealmente queste foto sarebbero solo decorazioni. - Usiamo WebP?
La compressione delle immagini è spesso considerata una rapida vittoria, ma nella pratica è ancora fortemente sottoutilizzata. Ovviamente le immagini non bloccano il rendering, ma contribuiscono pesantemente a scarsi punteggi LCP e molto spesso sono semplicemente troppo pesanti e troppo grandi per il dispositivo su cui vengono consumate.Quindi, come minimo, potremmo esplorare utilizzando il formato WebP per le nostre immagini. In effetti, la saga di WebP si è avvicinata alla fine lo scorso anno con Apple che ha aggiunto il supporto per WebP in Safari 14. Quindi, dopo molti anni di discussioni e dibattiti, ad oggi WebP è supportato in tutti i browser moderni. Quindi possiamo fornire immagini WebP con l'elemento
<picture>
e un fallback JPEG se necessario (vedi snippet di codice di Andreas Bovens) o utilizzando la negoziazione del contenuto (usando le intestazioniAccept
).Tuttavia, WebP non è privo di svantaggi . Sebbene le dimensioni dei file di immagine WebP siano confrontate con gli equivalenti Guetzli e Zopfli, il formato non supporta il rendering progressivo come JPEG, motivo per cui gli utenti potrebbero vedere l'immagine finita più velocemente con un buon vecchio JPEG anche se le immagini WebP potrebbero diventare più veloci attraverso la rete. Con JPEG, possiamo offrire un'esperienza utente "decente" con la metà o addirittura un quarto dei dati e caricare il resto in un secondo momento, piuttosto che avere un'immagine semivuota come nel caso di WebP.
La tua decisione dipenderà da cosa cerchi: con WebP ridurrai il carico utile e con JPEG migliorerai le prestazioni percepite. Puoi saperne di più su WebP in WebP Rewind talk di Pascal Massimino di Google.
Per la conversione in WebP, puoi utilizzare WebP Converter, cwebp o libwebp. Anche Ire Aderinokun ha un tutorial molto dettagliato sulla conversione delle immagini in WebP, così come Josh Comeau nel suo pezzo sull'adozione dei moderni formati di immagine.
Sketch supporta nativamente WebP e le immagini WebP possono essere esportate da Photoshop utilizzando un plug-in WebP per Photoshop. Ma sono disponibili anche altre opzioni.
Se stai utilizzando WordPress o Joomla, ci sono estensioni per aiutarti a implementare facilmente il supporto per WebP, come Optimus e Cache Enabler per WordPress e l'estensione supportata da Joomla (tramite Cody Arsenault). Puoi anche astrarre l'elemento
<picture>
con React, componenti in stile o gatsby-image.Ah - spina spudorata! — Jeremy Wagner ha persino pubblicato un libro Smashing su WebP che potresti voler controllare se sei interessato a tutto ciò che riguarda WebP.
- Usiamo AVIF?
Potresti aver sentito la grande novità: l'AVIF è atterrato. È un nuovo formato immagine derivato dai fotogrammi chiave del video AV1. È un formato aperto e privo di royalty che supporta compressione, animazione, canale alfa con perdita e può gestire linee nitide e colori solidi (che era un problema con JPEG), fornendo risultati migliori in entrambi.Infatti, rispetto a WebP e JPEG, AVIF ha prestazioni significativamente migliori , producendo risparmi sulla dimensione media del file fino al 50% con la stessa ((dis)somiglianza DSSIM tra due o più immagini utilizzando un algoritmo che si avvicina alla visione umana). In effetti, nel suo post approfondito sull'ottimizzazione del caricamento delle immagini, Malte Ubl osserva che AVIF "supera costantemente JPEG in modo molto significativo. Questo è diverso da WebP che non produce sempre immagini più piccole di JPEG e potrebbe effettivamente essere un net- perdita per mancanza di supporto per il caricamento progressivo."
Ironia della sorte, AVIF può funzionare anche meglio dei grandi SVG, anche se ovviamente non dovrebbe essere visto come un sostituto degli SVG. È anche uno dei primi formati di immagine a supportare il supporto del colore HDR; offrendo maggiore luminosità, profondità di bit di colore e gamme di colori. L'unico aspetto negativo è che attualmente AVIF non supporta la decodifica progressiva delle immagini (ancora?) e, analogamente a Brotli, una codifica ad alto tasso di compressione è attualmente piuttosto lenta, sebbene la decodifica sia veloce.
AVIF è attualmente supportato in Chrome, Firefox e Opera e il supporto in Safari dovrebbe arrivare presto (poiché Apple è un membro del gruppo che ha creato AV1).
Qual è il modo migliore per offrire immagini in questi giorni , allora? Per illustrazioni e immagini vettoriali, SVG (compresso) è senza dubbio la scelta migliore. Per le foto, utilizziamo metodi di negoziazione dei contenuti con l'elemento
picture
. Se l'AVIF è supportato, inviamo un'immagine AVIF; in caso contrario, torniamo prima a WebP e, se anche WebP non è supportato, passiamo a JPEG o PNG come fallback (applicando le condizioni@media
se necessario):<picture> <source type="image/avif"> <source type="image/webp"> <img src="image.jpg" alt="Photo" width="450" height="350"> </picture>
Francamente, è più probabile che utilizzeremo alcune condizioni all'interno dell'elemento
picture
:<picture> <source type="image/avif" /> <source type="image/webp" /> <source type="image/jpeg" /> <img src="fallback-image.jpg" alt="Photo" width="450" height="350"> </picture>
<picture> <source type="image/avif" /> <source type="image/webp" /> <source type="image/jpeg" /> <img src="fallback-image.jpg" alt="Photo" width="450" height="350"> </picture>
Puoi andare ancora oltre scambiando immagini animate con immagini statiche per i clienti che optano per meno movimento con
prefers-reduced-motion
:<picture> <source media="(prefers-reduced-motion: reduce)" type="image/avif"></source> <source media="(prefers-reduced-motion: reduce)" type="image/jpeg"></source> <source type="image/avif"></source> <img src="motion.jpg" alt="Animated AVIF"> </picture>
<picture> <source media="(prefers-reduced-motion: reduce)" type="image/avif"></source> <source media="(prefers-reduced-motion: reduce)" type="image/jpeg"></source> <source type="image/avif"></source> <img src="motion.jpg" alt="Animated AVIF"> </picture>
Nel corso dei due mesi, AVIF ha guadagnato terreno:
- Possiamo testare i fallback WebP/AVIF nel pannello Rendering in DevTools.
- Possiamo usare Squoosh, AVIF.io e libavif per codificare, decodificare, comprimere e convertire file AVIF.
- Possiamo usare il componente AVIF Preact di Jake Archibald che decodifica un file AVIF in un lavoratore e visualizza il risultato su una tela,
- Per fornire AVIF solo ai browser di supporto, possiamo utilizzare un plug-in PostCSS insieme a uno script 315B per utilizzare AVIF nelle dichiarazioni CSS.
- Siamo in grado di fornire progressivamente nuovi formati di immagine con CSS e Cloudlare Workers per alterare dinamicamente il documento HTML restituito, deducendo le informazioni dall'intestazione di
accept
e quindi aggiungere lewebp/avif
ecc. a seconda dei casi. - AVIF è già disponibile in Cloudinary (con limiti di utilizzo), Cloudflare supporta AVIF in Image Resizing e puoi abilitare AVIF con intestazioni AVIF personalizzate in Netlify.
- Quando si tratta di animazione, AVIF si comporta così come
<img src=mp4>
di Safari, superando GIF e WebP in generale, ma MP4 ha comunque prestazioni migliori. - In generale, per le animazioni, AVC1 (h264) > HVC1 > WebP > AVIF > GIF, supponendo che i browser basati su Chromium supportino sempre
<img src=mp4>
. - Puoi trovare maggiori dettagli su AVIF in AVIF per il discorso sulla codifica delle immagini di nuova generazione di Aditya Mavlankar da Netflix e nel discorso sul formato immagine AVIF di Kornel Lesinski di Cloudflare.
- Un ottimo riferimento per tutto AVIF: il post completo di Jake Archibald su AVIF è arrivato.
Quindi il futuro AVIF è allora ? Jon Sneyers non è d'accordo: AVIF ha prestazioni peggiori del 60% rispetto a JPEG XL, un altro formato gratuito e aperto sviluppato da Google e Cloudinary. In effetti, JPEG XL sembra funzionare molto meglio su tutta la linea. Tuttavia, JPEG XL è ancora solo nelle fasi finali della standardizzazione e non funziona ancora in nessun browser. (Da non confondere con il JPEG-XR di Microsoft proveniente dal buon vecchio Internet Explorer 9 volte).
- I file JPEG/PNG/SVG sono ottimizzati correttamente?
Quando lavori su una pagina di destinazione in cui è fondamentale che l'immagine di un eroe si carichi in modo incredibilmente veloce, assicurati che i JPEG siano progressivi e compressi con mozJPEG (che migliora il tempo di rendering iniziale manipolando i livelli di scansione) o Guetzli, l'open source di Google codificatore incentrato sulle prestazioni percettive e sull'utilizzo degli apprendimenti di Zopfli e WebP. L'unico aspetto negativo: tempi di elaborazione lenti (un minuto di CPU per megapixel).Per PNG possiamo usare Pingo e per SVG possiamo usare SVGO o SVGOMG. E se hai bisogno di visualizzare in anteprima e copiare o scaricare rapidamente tutte le risorse SVG da un sito Web, svg-grabber può farlo anche per te.
Ogni singolo articolo sull'ottimizzazione delle immagini lo direbbe, ma vale sempre la pena ricordare di mantenere le risorse vettoriali pulite e compatte. Assicurati di ripulire le risorse inutilizzate, rimuovere i metadati non necessari e ridurre il numero di punti di percorso nella grafica (e quindi il codice SVG). ( Grazie, Jeremy! )
Ci sono anche utili strumenti online disponibili però:
- Usa Squoosh per comprimere, ridimensionare e manipolare le immagini ai livelli di compressione ottimali (lossy o lossless),
- Usa Guetzli.it per comprimere e ottimizzare le immagini JPEG con Guetzli, che funziona bene per immagini con bordi netti e colori solidi (ma potrebbe essere un po' più lento)).
- Utilizza Responsive Image Breakpoints Generator o un servizio come Cloudinary o Imgix per automatizzare l'ottimizzazione delle immagini. Inoltre, in molti casi, l'utilizzo
srcset
esizes
da solo raccoglierà vantaggi significativi. - Per verificare l'efficienza del tuo markup reattivo, puoi utilizzare imaging-heap, uno strumento a riga di comando che misura l'efficienza tra le dimensioni del viewport e i rapporti pixel del dispositivo.
- Puoi aggiungere la compressione automatica delle immagini ai tuoi flussi di lavoro GitHub, in modo che nessuna immagine possa raggiungere la produzione non compressa. L'azione utilizza mozjpeg e libvips che funzionano con PNG e JPG.
- Per ottimizzare l'archiviazione internamente, puoi utilizzare il nuovo formato Lepton di Dropbox per comprimere i file JPEG senza perdite di una media del 22%.
- Usa BlurHash se desideri mostrare un'immagine segnaposto in anticipo. BlurHash prende un'immagine e ti dà una breve stringa (solo 20-30 caratteri!) che rappresenta il segnaposto per questa immagine. La stringa è abbastanza corta da poter essere facilmente aggiunta come campo in un oggetto JSON.
A volte l'ottimizzazione delle immagini da sola non basta. Per migliorare il tempo necessario per avviare il rendering di un'immagine critica, carica in modo lazy le immagini meno importanti e rinvia gli script da caricare dopo che le immagini critiche sono già state renderizzate. Il modo più a prova di proiettile è il lazy-loading ibrido, quando utilizziamo il lazy-loading e lazyload nativi, una libreria che rileva eventuali modifiche alla visibilità attivate dall'interazione dell'utente (con IntersectionObserver che esploreremo in seguito). Inoltre:
- Prendi in considerazione il precaricamento delle immagini critiche, in modo che un browser non le scopra troppo tardi. Per le immagini di sfondo, se vuoi essere ancora più aggressivo, puoi aggiungere l'immagine come un'immagine normale con
<img src>
, quindi nasconderla dallo schermo. - Considerare lo scambio di immagini con l'attributo Dimensioni specificando diverse dimensioni di visualizzazione dell'immagine a seconda delle query multimediali, ad esempio per manipolare le
sizes
per scambiare le sorgenti in un componente lente di ingrandimento. - Esamina le incoerenze di download delle immagini per evitare download imprevisti per le immagini in primo piano e di sfondo. Fai attenzione alle immagini che vengono caricate per impostazione predefinita, ma potrebbero non essere mai visualizzate, ad esempio nei caroselli, nelle fisarmoniche e nelle gallerie di immagini.
- Assicurati di impostare sempre
width
eheight
sulle immagini. Fai attenzione alla proprietàaspect-ratio
in CSS e all'attributointrinsicsize
che ci consentirà di impostare proporzioni e dimensioni per le immagini, in modo che il browser possa riservare uno slot di layout predefinito in anticipo per evitare salti di layout durante il caricamento della pagina.
Se ti senti avventuroso, puoi tagliare e riorganizzare i flussi HTTP/2 utilizzando Edge worker, fondamentalmente un filtro in tempo reale che vive sulla CDN, per inviare immagini più velocemente attraverso la rete. I lavoratori perimetrali utilizzano flussi JavaScript che utilizzano blocchi che puoi controllare (in pratica sono JavaScript che vengono eseguiti sul bordo CDN che possono modificare le risposte di streaming), in modo da poter controllare la consegna delle immagini.
Con un addetto ai servizi, è troppo tardi perché non puoi controllare cosa c'è sul cavo, ma funziona con i lavoratori Edge. Quindi puoi usarli sopra i JPEG statici salvati progressivamente per una particolare pagina di destinazione.
Non buono abbastanza? Bene, puoi anche migliorare le prestazioni percepite per le immagini con la tecnica delle immagini di sfondo multiple. Tieni presente che giocare con il contrasto e sfocare i dettagli non necessari (o rimuovere i colori) può anche ridurre le dimensioni del file. Ah, devi ingrandire una piccola foto senza perdere in qualità? Prendi in considerazione l'utilizzo di Letsenhance.io.
Queste ottimizzazioni finora coprono solo le basi. Addy Osmani ha pubblicato una guida molto dettagliata sull'ottimizzazione dell'immagine essenziale che approfondisce i dettagli della compressione dell'immagine e della gestione del colore. Ad esempio, potresti sfocare parti non necessarie dell'immagine (applicando loro un filtro sfocatura gaussiana) per ridurre le dimensioni del file e alla fine potresti persino iniziare a rimuovere i colori o trasformare l'immagine in bianco e nero per ridurre ulteriormente le dimensioni . Per le immagini di sfondo, anche l'esportazione di foto da Photoshop con una qualità dallo 0 al 10% può essere assolutamente accettabile.
Su Smashing Magazine, utilizziamo il suffisso
-opt
per i nomi delle immagini, ad esempiobrotli-compression-opt.png
; ogni volta che un'immagine contiene quel suffisso, tutti nel team sanno che l'immagine è già stata ottimizzata.Ah, e non utilizzare JPEG-XR sul Web: "l'elaborazione della decodifica di JPEG-XR lato software sulla CPU annulla e addirittura supera l'impatto potenzialmente positivo del risparmio di dimensioni dei byte, specialmente nel contesto delle SPA" (non da confondere con Cloudinary/JPEG XL di Google però).
- I video sono ottimizzati correttamente?
Finora abbiamo trattato le immagini, ma abbiamo evitato una conversazione sulle buone vecchie GIF. Nonostante il nostro amore per le GIF, è davvero il momento di abbandonarle per sempre (almeno nei nostri siti Web e app). Invece di caricare GIF animate pesanti che influiscono sia sulle prestazioni di rendering che sulla larghezza di banda, è una buona idea passare a WebP animato (con GIF come fallback) o sostituirle con video HTML5 in loop del tutto.A differenza delle immagini, i browser non precaricano il contenuto
<video>
, ma i video HTML5 tendono ad essere molto più leggeri e più piccoli delle GIF. Non è un'opzione? Bene, almeno possiamo aggiungere una compressione con perdita di dati alle GIF con Lossy GIF, gifsicle o giflossy.I test di Colin Bendell mostrano che i video inline all'interno dei tag
img
in Safari Technology Preview vengono visualizzati almeno 20 volte più velocemente e decodificano 7 volte più velocemente dell'equivalente GIF, oltre ad essere una frazione delle dimensioni del file. Tuttavia, non è supportato in altri browser.Nella terra delle buone notizie, i formati video sono progrediti enormemente nel corso degli anni. Per molto tempo abbiamo sperato che WebM diventasse il formato per dominarli tutti e WebP (che è fondamentalmente un'immagine fissa all'interno del contenitore video WebM) diventasse un sostituto per formati di immagine datati. In effetti, Safari ora supporta WebP, ma nonostante WebP e WebM abbiano ottenuto supporto in questi giorni, la svolta in realtà non è avvenuta.
Tuttavia, potremmo utilizzare WebM per la maggior parte dei browser moderni disponibili:
<!-- By Houssein Djirdeh. https://web.dev/replace-gifs-with-videos/ --> <!-- A common scenartio: MP4 with a WEBM fallback. --> <video autoplay loop muted playsinline> <source src="my-animation.webm" type="video/webm"> <source src="my-animation.mp4" type="video/mp4"> </video>
Ma forse potremmo rivisitarlo del tutto. Nel 2018, l'Alliance of Open Media ha rilasciato un nuovo promettente formato video chiamato AV1 . AV1 ha una compressione simile al codec H.265 (l'evoluzione di H.264) ma a differenza di quest'ultimo, AV1 è gratuito. Il prezzo della licenza H.265 ha spinto i fornitori di browser ad adottare invece un AV1 con prestazioni comparabili: AV1 (proprio come H.265) si comprime due volte meglio di WebM .
In effetti, Apple attualmente utilizza il formato HEIF e HEVC (H.265) e tutte le foto e i video sull'ultimo iOS vengono salvati in questi formati, non JPEG. Sebbene HEIF e HEVC (H.265) non siano adeguatamente esposti al Web (ancora?), AV1 lo è e sta ottenendo il supporto del browser. Quindi aggiungere la sorgente
AV1
nel tag<video>
è ragionevole, poiché tutti i fornitori di browser sembrano essere d'accordo.Per ora, la codifica più utilizzata e supportata è H.264, servita da file MP4, quindi prima di servire il file, assicurati che i tuoi MP4 siano elaborati con una codifica multipass, sfocata con l'effetto frei0r iirblur (se applicabile) e I metadati di moov atom vengono spostati nella parte iniziale del file, mentre il tuo server accetta la pubblicazione di byte. Boris Schapira fornisce istruzioni esatte per FFmpeg per ottimizzare i video al massimo. Naturalmente, anche fornire il formato WebM in alternativa aiuterebbe.
Devi iniziare a eseguire il rendering dei video più velocemente ma i file video sono ancora troppo grandi ? Ad esempio, ogni volta che hai un video di sfondo di grandi dimensioni su una pagina di destinazione? Una tecnica comune da utilizzare consiste nel mostrare prima il primo fotogramma come immagine fissa, oppure visualizzare un breve segmento di loop fortemente ottimizzato che potrebbe essere interpretato come parte del video, quindi, ogni volta che il video è sufficientemente bufferizzato, avviare la riproduzione il video vero e proprio. Doug Sillars ha scritto una guida dettagliata alle prestazioni dei video in background che potrebbe essere utile in questo caso. ( Grazie, Guy Podjarny! ).
Per lo scenario precedente, potresti voler fornire immagini poster reattive . Per impostazione predefinita, gli elementi
video
consentono solo un'immagine come poster, il che non è necessariamente ottimale. Possiamo utilizzare Responsive Video Poster, una libreria JavaScript che ti consente di utilizzare immagini poster diverse per schermi diversi, aggiungendo anche una sovrapposizione di transizione e un controllo completo dello stile dei segnaposto video.La ricerca mostra che la qualità del flusso video influisce sul comportamento degli spettatori. Infatti, gli spettatori iniziano ad abbandonare il video se il ritardo di avvio supera i 2 secondi circa. Oltre tale punto, un aumento di 1 secondo del ritardo si traduce in un aumento di circa il 5,8% del tasso di abbandono. Quindi non sorprende che l'ora mediana di inizio del video sia 12,8 secondi, con il 40% dei video con almeno 1 stallo e il 20% almeno 2 secondi di riproduzione video bloccata. In effetti, gli stalli video sono inevitabili su 3G poiché i video vengono riprodotti più velocemente di quanto la rete possa fornire contenuti.
Allora, qual è la soluzione? Di solito i dispositivi con schermo piccolo non sono in grado di gestire i 720p e i 1080p che stiamo servendo sul desktop. Secondo Doug Sillars, possiamo creare versioni più piccole dei nostri video e utilizzare Javascript per rilevare la fonte per schermi più piccoli per garantire una riproduzione veloce e fluida su questi dispositivi. In alternativa, possiamo utilizzare lo streaming video. I flussi video HLS forniranno un video di dimensioni adeguate al dispositivo, eliminando la necessità di creare video diversi per schermi diversi. Negozierà anche la velocità della rete e adatterà il bitrate video alla velocità della rete che stai utilizzando.
Per evitare lo spreco di larghezza di banda, potremmo aggiungere la sorgente video solo per i dispositivi che effettivamente possono riprodurre bene il video. In alternativa, possiamo rimuovere del tutto l'attributo di riproduzione
autoplay
dal tagvideo
e utilizzare JavaScript per inserire laautoplay
per schermi più grandi. Inoltre, dobbiamo aggiungerepreload="none"
sulvideo
per dire al browser di non scaricare nessuno dei file video fino a quando non ha effettivamente bisogno del file:<!-- Based on Doug Sillars's post. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ --> <video preload="none" playsinline muted loop width="1920" height="1080" poster="poster.jpg"> <source src="video.webm" type="video/webm"> <source src="video.mp4" type="video/mp4"> </video>
Quindi possiamo indirizzare specificamente i browser che supportano effettivamente AV1:
<!-- Based on Doug Sillars's post. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ --> <video preload="none" playsinline muted loop width="1920" height="1080" poster="poster.jpg"> <source src="video.av1.mp4" type="video/mp4; codecs=av01.0.05M.08"> <source src="video.hevc.mp4" type="video/mp4; codecs=hevc"> <source src="video.webm" type="video/webm"> <source src="video.mp4" type="video/mp4"> </video>
Potremmo quindi aggiungere nuovamente l'
autoplay
oltre una certa soglia (es. 1000px):/* By Doug Sillars. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ */ <script> window.onload = addAutoplay(); var videoLocation = document.getElementById("hero-video"); function addAutoplay() { if(window.innerWidth > 1000){ videoLocation.setAttribute("autoplay",""); }; } </script>
Le prestazioni di riproduzione video sono una storia a sé stante e, se desideri approfondire i dettagli, dai un'occhiata a un'altra serie di Doug Sillars su The Current State of Video and Video Delivery Best Practices che include dettagli sulle metriche di consegna video , precaricamento, compressione e streaming video. Infine, puoi verificare quanto sarà lento o veloce il tuo streaming video con Stream or Not.
- La consegna dei caratteri web è ottimizzata?
La prima domanda che vale la pena porsi è se possiamo farla franca utilizzando i caratteri del sistema dell'interfaccia utente in primo luogo: dobbiamo solo assicurarci di ricontrollare che appaiano correttamente su varie piattaforme. In caso contrario, è molto probabile che i caratteri Web che stiamo servendo includano glifi e funzionalità e pesi extra che non vengono utilizzati. Possiamo chiedere alla nostra fonderia di tipi di sottoimpostare i caratteri Web o, se stiamo utilizzando caratteri open source, sottoimpostarli da soli con Glyphhanger o Fontsquirrel. Possiamo persino automatizzare l'intero flusso di lavoro con il sottocarattere di Peter Muller, uno strumento da riga di comando che analizza staticamente la tua pagina per generare i sottoinsiemi di caratteri Web più ottimali e quindi iniettarli nelle nostre pagine.Il supporto di WOFF2 è ottimo e possiamo utilizzare WOFF come fallback per i browser che non lo supportano, o forse i browser legacy potrebbero essere serviti come font di sistema. Esistono molte, molte, molte opzioni per il caricamento dei caratteri Web e possiamo scegliere una delle strategie della "Guida completa alle strategie di caricamento dei caratteri" di Zach Leatherman (snippet di codice disponibili anche come ricette di caricamento dei caratteri Web).
Probabilmente le migliori opzioni da considerare oggi sono Critical FOFT con
preload
e il metodo "The Compromise". Entrambi utilizzano un rendering a due fasi per fornire i caratteri Web in più fasi: prima un piccolo supersottoinsieme necessario per eseguire il rendering della pagina in modo rapido e accurato con il carattere Web, quindi caricare il resto della famiglia in modo asincrono. La differenza è che la tecnica "The Compromise" carica il polyfill in modo asincrono solo se gli eventi di caricamento dei font non sono supportati, quindi non è necessario caricare il polyfill per impostazione predefinita. Hai bisogno di una vittoria veloce? Zach Leatherman ha un breve tutorial di 23 minuti e un case study per mettere in ordine i tuoi caratteri.In generale, potrebbe essere una buona idea utilizzare il suggerimento per la risorsa di
preload
per precaricare i caratteri, ma nel tuo markup includi i suggerimenti dopo il collegamento a CSS e JavaScript critici. Conpreload
, c'è un puzzle di priorità, quindi considera di iniettare elementirel="preload"
nel DOM appena prima degli script di blocco esterni. Secondo Andy Davies, "le risorse iniettate utilizzando uno script sono nascoste dal browser fino all'esecuzione dello script e possiamo utilizzare questo comportamento per ritardare quando il browser rileva il suggerimento dipreload
". Altrimenti, il caricamento dei caratteri ti costerà nel primo tempo di rendering.È una buona idea essere selettivi e scegliere i file che contano di più, ad esempio quelli che sono critici per il rendering o che ti aiuterebbero a evitare ridisposizioni di testo visibili e di disturbo. In generale, Zach consiglia di precaricare uno o due caratteri di ciascuna famiglia : ha anche senso ritardare il caricamento di alcuni caratteri se sono meno critici.
È diventato abbastanza comune usare il valore
local()
(che si riferisce a un font locale per nome) quando si definisce unafont-family
di font nella regola@font-face
:/* Warning! Not a good idea! */ @font-face { font-family: Open Sans; src: local('Open Sans Regular'), local('OpenSans-Regular'), url('opensans.woff2') format ('woff2'), url('opensans.woff') format('woff'); }
L'idea è ragionevole: alcuni popolari font open source come Open Sans vengono preinstallati con alcuni driver o app, quindi se il font è disponibile localmente, il browser non ha bisogno di scaricare il font web e può visualizzare il font locale carattere immediatamente. Come ha osservato Bram Stein, "sebbene un font locale corrisponda al nome di un font web, molto probabilmente non è lo stesso font . Molti font web differiscono dalla loro versione" desktop ". Il testo potrebbe essere visualizzato in modo diverso, alcuni caratteri potrebbero cadere tornando ad altri tipi di carattere, le funzionalità OpenType potrebbero mancare del tutto o l'altezza della linea potrebbe essere diversa."
Inoltre, poiché i caratteri tipografici si evolvono nel tempo, la versione installata localmente potrebbe essere molto diversa dal carattere Web, con caratteri molto diversi. Quindi, secondo Bram, è meglio non mischiare mai font e font web installati localmente nelle regole
@font-face
. Google Fonts ha seguito l'esempio disabilitandolocal()
sui risultati CSS per tutti gli utenti, ad eccezione delle richieste Android per Roboto.A nessuno piace aspettare che il contenuto venga visualizzato. Con il descrittore CSS
font-display
, possiamo controllare il comportamento di caricamento dei caratteri e consentire la leggibilità del contenuto immediatamente (confont-display: optional
) o quasi immediatamente (con un timeout di 3 secondi, a condizione che il carattere venga scaricato correttamente — confont-display: swap
). (Beh, è un po' più complicato di così.)Tuttavia, se desideri ridurre al minimo l'impatto dei ridisposizioni di testo, potremmo utilizzare l' API di caricamento dei caratteri (supportata in tutti i browser moderni). In particolare ciò significa che per ogni font, avremmo creato un oggetto
FontFace
, quindi proveremo a recuperarli tutti e solo successivamente applicarli alla pagina. In questo modo, raggruppiamo tutti i ridisegni caricando tutti i caratteri in modo asincrono, quindi passiamo dai caratteri di fallback al carattere Web esattamente una volta. Dai un'occhiata alla spiegazione di Zach, a partire dalle 32:15, e al frammento di codice):/* Load two web fonts using JavaScript */ /* Zach Leatherman: https://noti.st/zachleat/KNaZEg/the-five-whys-of-web-font-loading-performance#sWkN4u4 */ // Remove existing @font-face blocks // Create two let font = new FontFace("Noto Serif", /* ... */); let fontBold = new FontFace("Noto Serif, /* ... */); // Load two fonts let fonts = await Promise.all([ font.load(), fontBold.load() ]) // Group repaints and render both fonts at the same time! fonts.forEach(font => documents.fonts.add(font));
/* Load two web fonts using JavaScript */ /* Zach Leatherman: https://noti.st/zachleat/KNaZEg/the-five-whys-of-web-font-loading-performance#sWkN4u4 */ // Remove existing @font-face blocks // Create two let font = new FontFace("Noto Serif", /* ... */); let fontBold = new FontFace("Noto Serif, /* ... */); // Load two fonts let fonts = await Promise.all([ font.load(), fontBold.load() ]) // Group repaints and render both fonts at the same time! fonts.forEach(font => documents.fonts.add(font));
Per avviare un recupero molto precoce dei caratteri con l'API di caricamento dei caratteri in uso, Adrian Bece suggerisce di aggiungere uno spazio unificatore
nbsp;
nella parte superiore delbody
e nascondilo visivamente conaria-visibility: hidden
e una classe.hidden
:<body class="no-js"> <!-- ... Website content ... --> <div aria-visibility="hidden" class="hidden"> <!-- There is a non-breaking space here --> </div> <script> document.getElementsByTagName("body")[0].classList.remove("no-js"); </script> </body>
<body class="no-js"> <!-- ... Website content ... --> <div aria-visibility="hidden" class="hidden"> <!-- There is a non-breaking space here --> </div> <script> document.getElementsByTagName("body")[0].classList.remove("no-js"); </script> </body>
Questo va di pari passo con CSS che ha diverse famiglie di caratteri dichiarate per diversi stati di caricamento, con la modifica attivata dall'API di caricamento dei caratteri una volta che i caratteri sono stati caricati correttamente:
body:not(.wf-merriweather--loaded):not(.no-js) { font-family: [fallback-system-font]; /* Fallback font styles */ } .wf-merriweather--loaded, .no-js { font-family: "[web-font-name]"; /* Webfont styles */ } /* Accessible hiding */ .hidden { position: absolute; overflow: hidden; clip: rect(0 0 0 0); height: 1px; width: 1px; margin: -1px; padding: 0; border: 0; }
body:not(.wf-merriweather--loaded):not(.no-js) { font-family: [fallback-system-font]; /* Fallback font styles */ } .wf-merriweather--loaded, .no-js { font-family: "[web-font-name]"; /* Webfont styles */ } /* Accessible hiding */ .hidden { position: absolute; overflow: hidden; clip: rect(0 0 0 0); height: 1px; width: 1px; margin: -1px; padding: 0; border: 0; }
Se ti sei mai chiesto perché, nonostante tutte le tue ottimizzazioni, Lighthouse suggerisce ancora di eliminare le risorse di blocco del rendering (font), nello stesso articolo Adrian Bece fornisce alcune tecniche per rendere felice Lighthouse, insieme a un Gatsby Omni Font Loader, un font asincrono performante caricamento e plug-in per la gestione di Flash Of Unstyled Text (FOUT) per Gatsby.
Ora, molti di noi potrebbero utilizzare una CDN o un host di terze parti da cui caricare i caratteri Web. In generale, è sempre meglio ospitare autonomamente tutte le tue risorse statiche, se possibile, quindi considera l'utilizzo di google-webfonts-helper, un modo semplice per ospitare automaticamente Google Fonts. E se non è possibile, puoi forse delegare i file di Google Font tramite l'origine della pagina.
Vale la pena notare, tuttavia, che Google sta facendo un bel po' di lavoro fuori dagli schemi, quindi un server potrebbe aver bisogno di un po' di ritocco per evitare ritardi ( grazie, Barry! )
Questo è abbastanza importante soprattutto perché da Chrome v86 (rilasciato a ottobre 2020), le risorse cross-site come i caratteri non possono più essere condivise sulla stessa CDN, a causa della cache del browser partizionata. Questo comportamento è stato un'impostazione predefinita in Safari per anni.
Ma se non è affatto possibile, c'è un modo per ottenere i caratteri Google più veloci possibili con lo snippet di Harry Roberts:
<!-- By Harry Roberts. https://csswizardry.com/2020/05/the-fastest-google-fonts/ - 1. Preemptively warm up the fonts' origin. - 2. Initiate a high-priority, asynchronous fetch for the CSS file. Works in - most modern browsers. - 3. Initiate a low-priority, asynchronous fetch that gets applied to the page - only after it's arrived. Works in all browsers with JavaScript enabled. - 4. In the unlikely event that a visitor has intentionally disabled - JavaScript, fall back to the original method. The good news is that, - although this is a render-blocking request, it can still make use of the - preconnect which makes it marginally faster than the default. --> <!-- [1] --> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <!-- [2] --> <link rel="preload" as="style" href="$CSS&display=swap" /> <!-- [3] --> <link rel="stylesheet" href="$CSS&display=swap" media="print" onload="this.media='all'" /> <!-- [4] --> <noscript> <link rel="stylesheet" href="$CSS&display=swap" /> </noscript>
La strategia di Harry è di riscaldare preventivamente l'origine dei caratteri prima. Quindi avviamo un recupero asincrono ad alta priorità per il file CSS. Successivamente, avviamo un recupero asincrono a bassa priorità che viene applicato alla pagina solo dopo che è arrivata (con un trucco del foglio di stile di stampa). Infine, se JavaScript non è supportato, torniamo al metodo originale.
Ah, parlando di Google Fonts: puoi ridurre fino al 90% la dimensione delle richieste di Google Fonts dichiarando solo i caratteri che ti servono con
&text
. Inoltre, il supporto per la visualizzazione dei caratteri è stato aggiunto di recente anche a Google Fonts, quindi possiamo usarlo immediatamente.Una breve parola di cautela però. Se utilizzi
font-display: optional
, potrebbe non essere ottimale utilizzare anche ilpreload
in quanto attiverà in anticipo la richiesta di font Web (causando una congestione della rete se hai altre risorse di percorso critiche che devono essere recuperate). Usapreconnect
per richieste di font tra origini più veloci, ma fai attenzione con ilpreload
poiché il precaricamento dei font da un'origine diversa comporterà conflitti di rete. Tutte queste tecniche sono trattate nelle ricette di caricamento dei caratteri Web di Zach.D'altra parte, potrebbe essere una buona idea disattivare i caratteri Web (o almeno il rendering della seconda fase) se l'utente ha abilitato Riduci movimento nelle preferenze di accessibilità o ha optato per la modalità Risparmio dati (vedi intestazione
Save-Data
) o quando l'utente ha una connettività lenta (tramite Network Information API).Possiamo anche utilizzare la query multimediale CSS
prefers-reduced-data
per non definire le dichiarazioni dei caratteri se l'utente ha attivato la modalità di salvataggio dei dati (ci sono anche altri casi d'uso). La query multimediale mostrerebbe sostanzialmente se l'intestazione della richiestaSave-Data
dall'estensione HTTP Hint client è attivata/disattivata per consentire l'utilizzo con CSS. Attualmente supportato solo in Chrome e Edge dietro una bandiera.Metrica? Per misurare le prestazioni di caricamento dei caratteri Web, considera la metrica Tutto il testo visibile (il momento in cui tutti i caratteri sono stati caricati e tutto il contenuto viene visualizzato nei caratteri Web), Tempo per il corsivo reale e Conteggio riflusso dei caratteri Web dopo il primo rendering. Ovviamente, più basse sono entrambe le metriche, migliori saranno le prestazioni.
Che dire dei caratteri variabili , potresti chiedere? È importante notare che i caratteri variabili potrebbero richiedere una considerazione significativa delle prestazioni. Ci danno uno spazio di progettazione molto più ampio per le scelte tipografiche, ma viene al costo di una singola richiesta seriale rispetto a un numero di richieste di file individuali.
Sebbene i caratteri variabili riducano drasticamente le dimensioni complessive dei file di caratteri combinati, quella singola richiesta potrebbe essere lenta, bloccando il rendering di tutto il contenuto di una pagina. Quindi il sottoinsieme e la divisione del carattere in set di caratteri sono ancora importanti. Tra i lati positivi, tuttavia, con un carattere variabile in atto, otterremo esattamente un reflow per impostazione predefinita, quindi non sarà richiesto JavaScript per raggruppare i ridisegni.
Ora, cosa renderebbe allora una strategia di caricamento dei font web a prova di proiettile ? Sottoimposta i caratteri e preparali per il rendering in 2 fasi, dichiarali con un descrittore
font-display
, utilizza l'API di caricamento dei caratteri per raggruppare i ridisegni e archiviare i caratteri nella cache di un lavoratore del servizio permanente. Alla prima visita, iniettare il precaricamento degli script appena prima degli script esterni di blocco. Se necessario, potresti ricorrere a Font Face Observer di Bram Stein. E se sei interessato a misurare le prestazioni del caricamento dei caratteri, Andreas Marschke esplora il monitoraggio delle prestazioni con l'API dei caratteri e l'API UserTiming.Infine, non dimenticare di includere
unicode-range
per scomporre un carattere grande in caratteri più piccoli specifici della lingua e utilizzare il corrispettivo dello stile dei caratteri di Monica Dinculescu per ridurre al minimo uno spostamento stridente nel layout, a causa delle discrepanze di dimensioni tra il fallback e il caratteri web.In alternativa, per emulare un font web per un font di fallback, possiamo usare i descrittori @font-face per sovrascrivere le metriche dei font (demo, abilitato in Chrome 87). (Si noti che le regolazioni sono complicate con pile di caratteri complicate.)
Il futuro sembra luminoso? Con l'arricchimento progressivo dei caratteri, alla fine potremmo essere in grado di "scaricare solo la parte richiesta del carattere su una determinata pagina e, per le successive richieste di quel carattere, "rattoppare" dinamicamente il download originale con set aggiuntivi di glifi come richiesto nella pagina successiva visualizzazioni", come spiega Jason Pamental. La demo di trasferimento incrementale è già disponibile ed è in lavorazione.
Sommario
- Prepararsi: pianificazione e metriche
- Stabilire obiettivi realistici
- Definire l'ambiente
- Ottimizzazioni degli asset
- Costruisci ottimizzazioni
- Ottimizzazioni di consegna
- Rete, HTTP/2, HTTP/3
- Test e monitoraggio
- Vittorie veloci
- Tutto in una pagina
- Scarica la lista di controllo (PDF, Apple Pages, MS Word)
- Iscriviti alla nostra newsletter via email per non perdere le prossime guide.