Diario · Nota 001 · Prestazioni web
Dove si nascondevano gli ultimi 18 punti in un sito statico
Immagini compresse, JavaScript diviso in tre file, nessun framework. Lighthouse segnava comunque 82. I punti mancanti erano in tre aree che lo strumento nominava senza spiegare.
Fondatore, BLN Global · · 7 min di lettura
Risposta breve
Immagini e JavaScript erano già a posto. I punti mancanti si nascondevano altrove. Primo: il controllo pensato per evitare lavoro inutile leggeva il layout e costringeva il browser a ricalcolarlo. Secondo: il foglio di stile e i font esterni ritardavano di 600 ms il primo rendering. Abbiamo integrato il CSS nella pagina e ospitato i font sul nostro server. Terzo: dei 24 avvisi sul contrasto, 6 erano falsi positivi. La scansione completa ha poi trovato 13 pagine sfuggite al campione.
Questo sito non usa framework. Le pagine sono semplice HTML generato da script Python, lo stile sta in un solo file CSS e JavaScript occupa tre piccoli file. Le immagini sono in WebP e vengono prodotte in tre dimensioni. Tutti gli interventi più ovvi sulle prestazioni erano già stati fatti.
Il punteggio mobile era fermo a 82.
Sistemati i problemi evidenti, i punti rimasti non dipendevano da un unico grande errore. Erano sparsi in tre punti diversi. Per trovarli tutti, leggere gli avvisi dello strumento non bastava. cosa intendi ha richiesto di capire.
Al primo posto: il controllo scritto per evitare il lavoro
L’avviso "ricalcolo forzato" (forced reflow) di Lighthouse indica che JavaScript obbliga il browser a calcolare il layout troppo presto. Il browser accumula le modifiche agli stili per applicarle insieme. Se nel frattempo il codice legge una misura, deve elaborarle subito.
L’avviso indicava la riga sorgente, ma lì non si vedeva alcun valore. Trovato in tre passaggi.
- Al primo giro
getComputedStylechiamate rimosse. Il punteggio non si è mosso. - Al secondo giro è spuntato il vero colpevole: un
if (window.scrollY > 0)controllo. Il controllo stesso legge il layout. La riga scritta per evitare quel lavoro finiva per eseguirlo. - Al terzo tentativo abbiamo eliminato la funzione. Lo stato iniziale era già definito nel CSS. JavaScript non doveva ricrearlo.
Resta anche uno schema void element.offsetWidth era. Un trucco diffuso e accettato: forzava il layout apposta per riavviare una transizione. Lo abbiamo sostituito con due requestAnimationFrame È stato aggiunto. Fa lo stesso lavoro senza forzare il layout.
function riavvia(fn) { /* Se la scheda è in background, rAF non parte e la demo resta vuota. */ if (document.hidden) { fn(); return; } requestAnimationFrame(function () { requestAnimationFrame(fn); }); }
La lezione è questa: spesso un avviso sulle prestazioni non dice "stai facendo troppo", ma "lo stai facendo nel momento sbagliato".
Al secondo posto: i 600 ms prima del primo rendering
Il secondo avviso riguardava le risorse che bloccavano la prima visualizzazione. All’apertura, il browser non mostrava nulla finché non aveva scaricato ed elaborato prima il foglio di stile, poi i font. Il ritardo misurato era di 600 millisecondi.
Abbiamo inserito il foglio di stile nella pagina
Un file CSS separato alla seconda visita arriva dalla cache. È un vantaggio. Alla prima visita, però, aggiunge un viaggio in rete, e la prima visita è quella di chi arriva dai risultati di ricerca. Durante la pubblicazione riduciamo il CSS e lo inseriamo nella pagina. Lo abbiamo misurato: dopo la compressione Brotli, la versione incorporata pesava meno di file separato + seconda richiesta.
Abbiamo portato i font sul nostro server
L’assetto arrivato da Google Fonts chiamava due origini diverse: una per lo stile, fonts.googleapis.com, per i file fonts.gstatic.com. Ogni nuova origine richiede una risoluzione DNS, un handshake TLS e una nuova connessione. Eliminarla ha prodotto questo risultato:
I font scaricati da una pagina in turco. Da 6 file e 2 origini esterne a 3 file su una sola origine.
unicode-range guardando i campi, abbiamo separato i subset che la pagina turca avrebbe scaricato davvero (latin + latin-ext) e misurato i file uno per uno. Dall'altra parte, in questo repository, assets/fonts la dimensione reale dei file.Abbiamo dedicato una nota a come abbiamo ridotto i font e ai costi del passaggio a dieci lingue: dieci lingue, tre file font.
Terzo punto: dove lo strumento sbaglia
Il controllo di accessibilità ha segnalato 24 problemi di contrasto. Correggerli tutti avrebbe rovinato metà del design. 6 erano falsi positivi.
Motivo content-visibility:auto era. Questa funzione rimanda il rendering delle sezioni fuori schermo e accelera la prima visualizzazione. Esattamente ciò che volevamo. Il colore calcolato della sezione rimandata, però, non arrivava allo strumento di verifica, che segnalava «bianco su bianco». Sullo schermo non accadeva nulla del genere.
Abbiamo misurato i rapporti reali nel browser, uno per uno. 18 avvisi erano corretti e li abbiamo risolti. Gli altri 6 dipendevano da un limite dello strumento: content-visibility è stato tolto solo dalle due sezioni problematiche e lasciato nelle altre.
L’avviso di uno strumento di audit non prova che ci sia un errore da correggere. È un’ipotesi: la verifichi, poi intervieni. Questa lezione è tornata altre due volte su questo sito. Una era nella nota sul controllo lingua lo spieghiamo.
Poi c’è il danno che ci siamo fatti da soli
Per evitare salti di layout, assegna le dimensioni a ogni immagine width e height È stato aggiunto l'attributo. Scelta giusta: il browser può riservare lo spazio dell'immagine prima di scaricarla. Però i box della demo si sono rotti: alcune immagini sono state disegnate larghe 58 pixel e alte 1500 pixel.
Il motivo è questo: nell’HTML width e height gli attributi suggeriscono la resa e nel CSS height ne compilano il valore. Nel design, per quei riquadri c'è solo aspect-ratio era definito, height era vuoto. L’attributo si è infilato lì e ha falsato la percentuale. Correzione in una riga:
img{max-width:100%;height:auto;display:block}
E qui la scansione serve davvero
Con la home a 100 sembrava finita. Non lo era. Avevamo misurato un campione. Del sito tutte le 150 pagine le abbiamo passate una a una in Lighthouse. Risultato: 137 pagine a 100 in tutte e quattro le voci, non 13 pagine. Accessibilità, best practice e SEO erano a 100 su ogni pagina. Lo scarto stava solo nelle prestazioni.
Undici pagine su tredici erano nella stessa lingua: arabo. La più bassa era a 83.
/ar/safecoast/ 83 /ar/laya/ 84 /ar/localmind/ 84 /ar/adforge/ 85 /ar/garanti/ 85 /ar/gtin/ 86 /ar/visionguard/ 86 /ar/ 89 /ar/growthos/ 97 /ar/dream/ 99 /ar/twin/ 99
Lighthouse lo ha detto chiaramente: Font web caricato → ar.woff2. Il font arabo arrivava tardi e faceva ricomporre la pagina. Le metriche del font arabo di riserva erano molto diverse da Noto Sans Arabic, e lo spostamento diventava forte. La correzione riprendeva la scelta già fatta con Martian Mono: swap non optional.
Spostamenti di layout (CLS) nelle pagine arabe
La vera lezione non riguarda le prestazioni. Dire «il sito vale 100» dopo aver controllato solo un campione significa parlare anche delle pagine che non hai misurato. Per mesi, quindici pagine sono rimaste ferme a 83 punti. Non le avevamo mai guardate.
Il limite del risultato
Il punteggio nasce da un test di laboratorio. Presuppone un dispositivo e una rete fissi, mentre il telefono e la connessione di chi visita il sito possono essere peggiori. Misurata più volte di seguito, la stessa pagina oscilla tra 98 e 100. Un 100 non significa «veloce per tutti». Significa che abbiamo rimosso gli ostacoli misurabili. Quando avremo abbastanza dati reali, conteranno quelli sul campo raccolti da Chrome.
Queste tre correzioni hanno una cosa in comune: non chiedono più lavoro. Hanno tolto lavoro fatto nel momento sbagliato, o lavoro che non andava fatto.