Vai al contenuto
Allin

Formattare o minificare: a cosa serve ciascuno e cosa cambia sul peso

Pubblicato il 10/08/2026 · 14 min di lettura · Strumenti per sviluppatori

Daniel Okonkwo

Daniel OkonkwoSviluppatore front-end e redattore Tech presso Allin

Performance web · Formati di file

Verificato su 4 fonti

Vedi il profilo
In breve

Formattare serve a leggere; minificare serve a pubblicare. L'argomento del peso è molto più debole di quanto suggerisca il conteggio dei byte grezzi, perché tutto ciò che pubblichi passa da gzip e gzip gestisce già la ripetizione — e l'indentazione è il testo più ripetitivo che esista. Quattro fogli di stile sono passati in questo minificatore, annotando entrambe le dimensioni. Un componente card scritto a mano è passato da 1 612 a 1 118 byte, un taglio del 30,6%; con gzip, da 659 a 555, un risparmio di 104 byte. Separare le due passate è la lezione vera. Sugli stessi quattro file, togliere i soli spazi ha fatto risparmiare 48, 103, 104 e 147 byte compressi — un centinaio, qualunque sia la dimensione, da 1,6 kB a 22 kB. Togliere i soli commenti ne ha fatti risparmiare 57, 1 358, 2 420 e 1 042. Su un file molto commentato i commenti sono il 96% del risparmio reale; gli spazi, un errore di arrotondamento. Minifica quindi per i commenti e il codice morto, non per gli a capo, e mai a scapito della correttezza. Questo minificatore sono cinque espressioni regolari e rompe cinque cose: cancella lo spazio che il CSS richiede ai due lati del + dentro calc(), quindi calc(100% + 16px) diventa una dichiarazione non valida che il browser scarta; modifica l'interno delle stringhe e trasforma content: "a; b" in "a;b"; cancella una stringa che sembra soltanto un commento; si mangia una sequenza di commento dentro un data URI; e riscrive a[title="hello, world"]. Lo stesso sito offre css-compressor, uno scanner che non ne rompe nessuna e pesa 2 byte in più su un file da 22 746 byte.

Quattro fogli di stile veri passati nel minificatore, misurati grezzi e dopo gzip. Togliere tutti gli spazi ha fatto risparmiare 48, 103, 104 e 147 byte compressi; togliere i commenti 57, 1 358, 2 420 e 1 042. E i cinque input che questo minificatore rompe.

La misura che quasi tutti gli articoli saltano: dopo gzip

Un minificatore riporta il conteggio dei byte grezzi perché è l'unico che sa calcolare. Non è quello che viaggia. Ogni foglio di stile servito via HTTP arriva compresso, e le due operazioni si sovrappongono: gzip codifica una sequenza di byte ripetuti come un breve riferimento all'indietro, e quattro spazi di indentazione ripetuti trecento volte sono la cosa più economica che incontrerà mai. Togliere quell'indentazione prima di comprimere elimina un lavoro che gzip faceva gratis.

Le due passate sono quindi state separate e misurate ciascuna per conto suo. Togliere solo i commenti, poi solo gli spazi, poi entrambi, su quattro file: un componente card scritto a mano da 1 612 byte e tre fogli di stile presi così come sono dal repository di questo sito. Compressa con gzip livello 9, la passata degli spazi ha fatto risparmiare 48, 103, 104 e 147 byte. Non percentuali: byte, e all'incirca lo stesso centinaio sia che il file pesasse 1,6 kB sia 22 kB, perché in un foglio di stile c'è solo un numero limitato di indentazioni distinte per quanto lungo diventi. La passata dei commenti, sugli stessi quattro file, ha fatto risparmiare 57, 1 358, 2 420 e 1 042 byte compressi.

Un file basta a dimostrarlo. Il globals.css di questo sito pesa 7 148 byte, buona parte dei quali è prosa che spiega perché ogni colore è stato scelto. Togliere gli spazi lo ha portato da 3 140 byte gzippati a 3 036: 104 byte, il 3,3%. Togliere i commenti lo ha portato a 720, un risparmio di 2 420 byte, il 77%. Il novantasei per cento del guadagno reale veniva dai commenti, e nulla dagli a capo. Ecco tutto l'argomento in un solo file: minifica per togliere ciò che il browser non può usare, non per togliere ciò di cui il compressore già si occupa.

Formattare non costa quasi nulla una volta compresso

La simmetria vale anche nell'altro senso, ed è la parte utile. L'esempio fornito dal formattatore HTML è una pagina minificata da 485 byte. Formattata con indentazione di due spazi diventa 627 byte: 142 in più, un aumento del 29,3%, il numero che mette in agitazione. Con gzip passa da 343 a 369 byte: 26 byte, il 7,6%. Ventisei byte non sono nulla. Se pubblichi una pagina leggibile per un motivo — un esempio di documentazione, un modello di email che qualcuno deve modificare, una pagina di cui vuoi che si possa vedere il sorgente — il costo compresso della leggibilità è inferiore a una richiesta di favicon.

Il formattatore HTML merita anche di essere capito per ciò che si rifiuta di fare. Copia il contenuto di pre e textarea byte per byte, perché i loro spazi vengono resi. Mantiene un singolo spazio fra due elementi in linea, perché toglierlo attaccherebbe due parole sullo schermo. E non tocca un attributo tra virgolette, quindi title="a > b" sopravvive intatto invece di essere tagliato alla parentesi angolare. I tre comportamenti sono stati verificati direttamente e tutti e tre reggono.

Un punto cieco ce l'ha, ed è proprio quello che il suo stesso commento sostiene di aver chiuso. Due pulsanti separati da uno spazio — <div><button>A</button> <button>B</button></div> — escono dal minificatore come <button>A</button><button>B</button>. I pulsanti sono inline-block, quindi quello spazio viene disegnato, e lo stacco fra i due pulsanti sparisce. La regola applicata è che lo spazio fra due tag di blocco è invisibile, e la sua lista di elementi in linea contiene a, b, span, code e un'altra ventina, ma non button, né select, né un'immagine dentro un link. Controlla ogni fila di pulsanti dopo la minificazione.

Cinque input che questo minificatore CSS sbaglia

La pagina css-minifier sono cinque espressioni regolari: togliere i commenti, ridurre le sequenze di spazi a uno solo, eliminare gli spazi attorno a un insieme di segni di punteggiatura, togliere un punto e virgola prima di una graffa di chiusura, rifilare. Basta per un foglio di stile che hai scritto un'ora fa e non basta per nient'altro, perché un'espressione regolare non distingue la struttura dal contenuto.

Il primo fallimento è quello grave. CSS Values and Units Level 3 dice, nella sintassi di calc(), che è richiesto uno spazio da entrambi i lati degli operatori + e -. L'elenco di punteggiatura qui contiene il +, quindi calc(100% + 16px) esce come calc(100%+16px) e l'intera dichiarazione è non valida: il browser la scarta e ripiega su ciò che c'era prima. Poiché il - non è nell'elenco, calc(100% - 16px) sopravvive intatto, il che è peggio — metà delle tue espressioni calc funziona e l'altra metà sparisce in silenzio. Non è un caso inventato. Il file apps/web/components/app/app-shell.module.css di questo repository contiene calc(74px + env(safe-area-inset-bottom)), il riempimento che tiene la barra delle schede mobile lontana dall'indicatore home. Passalo in questo strumento e quel riempimento è sparito.

Le altre quattro nascono dalla stessa radice: le stringhe e i data URI sono contenuto, e le passate li trattano come struttura. content: "a; b" diventa content:"a;b", perché il punto e virgola è nell'elenco di punteggiatura. content: "{ }" diventa content:"{}". a[title="hello, world"] diventa a[title="hello,world"] e il selettore smette di corrispondere. Un foglio di stile la cui stringa content contiene i caratteri che aprono e chiudono un commento CSS — content: "/* not a comment */" — esce come content:"", con la stringa svuotata. E un'immagine di sfondo scritta come data URI che per caso contenga quella stessa sequenza di due caratteri perde tutto ciò che sta in mezzo: url("data:image/svg+xml,...%3E/*x*/%3C...") arriva con il centro cancellato e l'immagine morta.

Due cose che non rompe, per equilibrio. Le proprietà personalizzate sopravvivono: --shadow: 0 2px 8px rgba(0, 0, 0, 0.1) esce come --shadow:0 2px 8px rgba(0,0,0,0.1), lo stesso valore. Sopravvivono anche le media query: @media screen and (min-width: 600px) diventa @media screen and (min-width:600px), ancora valida, e la sintassi di intervallo moderna @media (400px <= width <= 700px) resta intatta, perché <= non è nell'elenco di punteggiatura.

Due minificatori sullo stesso sito, e quello sicuro pesa 2 byte in più

La pagina css-compressor usa un altro motore. Invece di riconoscere schemi, percorre il file carattere per carattere e marca ciascuno come struttura o letterale: tutto ciò che sta dentro una stringa, un commento o una coppia di parentesi è letterale, e nessuna trasformazione può toccarlo. È quell'unico indicatore a preservare un data URI, un'espressione calc() e i decimali di un rgba().

Tutto il senso dell'approccio ingenuo doveva essere il minor peso. Non lo è. Entrambi sono stati eseguiti sugli stessi tre fogli di stile veri. Su app-shell.module.css, 22 746 byte in ingresso, la versione a espressioni regolari ha prodotto 19 278 byte e lo scanner 19 280 — 2 byte di differenza, e con gzip lo scanner era addirittura 1 byte più piccolo, 4 191 contro 4 192. Su admin.css lo scarto è stato di 1 byte grezzo e 2 byte gzippati. Su globals.css, di 8 byte grezzi. Otto byte, su un file dove la versione sicura mantiene lo spazio in @media (min-width: 600px) e in rgba(0, 0, 0, 0.1). Non c'è alcun argomento di dimensione a favore della versione a espressioni regolari; è semplicemente quella che ogni tanto distrugge il file.

L'SVG è l'eccezione, e ha il suo bug

Tutto quanto sopra dice che l'argomento del peso a favore della minificazione è debole. L'SVG è dove è forte, perché il peso di un SVG esportato non è fatto di spazi. Un piccolo disegno salvato da un editor vettoriale si porta dietro una dichiarazione XML, un commento dell'editor, un titolo, una descrizione, un blocco di metadati RDF, una vista nominata con l'ultimo livello di zoom, due namespace dell'editor, una trasformazione a matrice identità, uno spessore di tratto e un'opacità fissati ai propri valori predefiniti, e coordinate scritte con sette decimali. Passa un file simile — 1 071 byte — in svg-optimizer ed esce a 256 byte, un taglio del 76,1%. Con gzip: da 603 a 207, un taglio del 65,7%. Quel risparmio è reale perché il materiale rimosso è testo unico, e il testo unico è esattamente ciò con cui un compressore non può fare nulla.

Quella stessa esecuzione ha fatto emergere un difetto da conoscere prima di usarlo. I colori attraversano due fasi nell'ordine sbagliato: prima vengono accorciati, poi passati alla fase di arrotondamento dei numeri, che legge le cifre esadecimali come numeri. stroke="#000000" viene accorciato in #000 e poi arrotondato in #0. black diventa #0. red diventa #f0. E poiché il modello numerico accetta la notazione scientifica, un colore esadecimale le cui cifre circondano una e esplode: #e5e7eb esce come #e50000000eb, #1e293b come #1e+293b, #0e7490 come #0. La stessa fase riscrive url(#g-0010) in url(#g-10) lasciando intatto id="g-0010", così il gradiente a cui punta sparisce. Tutto questo è stato riprodotto in un browser vero, con le impostazioni predefinite. Disattivare l'opzione di arrotondamento dei numeri evita ogni caso, al prezzo di qualche byte di precisione.

Altri due punti sullo stesso strumento. Rimuove title e desc come metadati dell'editor — ma sono i due elementi che uno screen reader annuncia per un SVG, quindi un'icona accessibile smette di esserlo. Il suo controllo del markup malformato, invece, è di quelli accurati: un browser segnala un errore XML innestando un elemento chiamato parsererror, perciò cercare quel solo nome rifiuterebbe qualsiasi disegno valido che ne porti uno suo. Lo strumento interroga invece il motore: una volta per sessione analizza qualcosa di deliberatamente rotto, legge lo spazio dei nomi del marcatore che torna, e da lì in poi guarda solo là. Un disegno che contiene un elemento parsererror si ottimizza normalmente; un tag non chiuso continua a essere rifiutato.

Le due passate misurate separatamente su quattro file veri, byte grezzi e gzip livello 9
FileOriginale, grezzo / gzipSolo spazi, risparmio gzipSolo commenti, risparmio gzip
Componente card scritto a mano1 612 / 65948 byte57 byte
app-shell.module.css (denso, pochi commenti)22 746 / 5 661103 byte1 358 byte
globals.css (molto commentato)7 148 / 3 140104 byte2 420 byte
admin.css4 767 / 1 855147 byte1 042 byte
SVG esportato da un editor, ottimizzatore completo1 071 / 603Metadati, non spazi396 byte, 65,7%
Minificatore CSSRiduci il CSS rimuovendo commenti e spazi inutili.Prova lo strumento

Domande frequenti

Vale ancora la pena minificare il CSS se il server comprime tutto con gzip?
Sì, ma per i commenti, non per gli spazi. Sui quattro file misurati qui, togliere tutti gli spazi e gli a capo ha fatto risparmiare 48, 103, 104 e 147 byte gzippati — un centinaio di byte ciascuno, sia che il file pesasse 1,6 kB sia 22 kB, perché gzip codifica l'indentazione ripetuta quasi gratis. Togliere i commenti ha fatto risparmiare 57, 1 358, 2 420 e 1 042 byte gzippati sugli stessi file. Se il tuo foglio di stile è documentato, i commenti sono tutto il risparmio; se non lo è, minificarlo ti darà circa un decimo di kilobyte e lo sforzo sarebbe meglio speso in una passata sul CSS inutilizzato. Ciò a cui la minificazione serve davvero, in una catena di build, è che arriva insieme alle passate che contano: togliere le regole che nulla nella pagina usa, unire le dichiarazioni duplicate, accorciare colori e unità.
Il mio layout si è rotto dopo la minificazione. Dove guardo per primo?
Cerca calc( nel file minificato e leggili tutti. Se uno contiene un più senza spazi attorno — calc(100%+16px) — quella dichiarazione non è valida e il browser la ignora. Il CSS richiede uno spazio da entrambi i lati di + e - dentro calc(), e un minificatore a espressioni regolari che stringe la punteggiatura lo cancella. Poi cerca content: e ogni selettore di attributo che contenga una virgola o un punto e virgola, perché un minificatore ingenuo modifica l'interno delle stringhe. Guarda quindi i data URI: se uno conteneva i due caratteri che aprono un commento CSS e più avanti i due che lo chiudono, tutto ciò che stava in mezzo è stato rimosso. Infine confronta il numero di regole prima e dopo; se è calato, si è perso qualcosa di strutturale, non solo spazi.
Devo formattare un file minificato che non ho scritto, prima di modificarlo?
Sì, ed è l'uso onesto di un formattatore. Riformattare cambia solo gli spazi, quindi non può alterare il comportamento, e trasforma un file su una riga sola in qualcosa che un diff sa descrivere. Due avvertenze. Primo: un file formattato non è automaticamente un file sorgente — se l'originale è stato generato da Sass, TypeScript o una libreria di componenti, modificare l'output significa che la tua modifica sparisce alla build successiva. Secondo: formattare e poi riminificare non è sempre l'identità; sul motore HTML provato qui, un'andata e ritorno aggiunge uno spazio ai due lati del testo dentro ogni elemento non in linea, portando una pagina da 133 byte a 145 e poi restando stabile. Innocuo nel browser, ma non aspettarti indietro un file identico byte per byte.
Perché l'ottimizzatore SVG fa risparmiare molto più del minificatore CSS?
Perché rimuove materiale diverso. Un minificatore CSS toglie spazi e commenti; di spazi si occupa già il compressore, quindi contano solo i commenti. Un ottimizzatore SVG toglie metadati dell'editor, attributi predefiniti, gruppi vuoti e decimali superflui — tutto testo unico che un compressore non può ripiegare. Nel file misurato qui, 1 071 byte sono diventati 256 grezzi, e 603 byte gzippati sono diventati 207, un taglio del 65,7% che è sopravvissuto quasi intatto alla compressione. La lezione si generalizza: qualsiasi minificatore che si limiti a riformattare ti deluderà dopo gzip, e qualsiasi minificatore che cancelli contenuto no. Ed è anche per questo che cancellare contenuto è la parte da controllare.
Brotli è abbastanza diverso da gzip da cambiare la risposta?
No, la rafforza leggermente. Il foglio di stile della card si è compresso a 527 byte con Brotli contro 659 con gzip, e minificato è sceso a 451 contro 555. Il risparmio assoluto della minificazione è stato di 76 byte con Brotli e di 104 con gzip: un compressore migliore lascia meno da togliere al minificatore, esattamente come ci si aspetta, dato che entrambi rimuovono la stessa ridondanza. Quindi se il tuo hosting serve Brotli — la maggior parte delle CDN lo fa — l'argomento a favore della minificazione degli spazi è ancora più debole, e quello a favore della rimozione dei commenti è invariato, perché un commento è testo unico con entrambi gli algoritmi.

Articoli che potrebbero interessarti

Tutte le guide
GuidaChe cosa può togliere un minificatore e che cosa non deve toccareLa minificazione deve preservare il significato, e la parte interessante è lo spazio bianco che porta significato: il combinatore discendente, gli spazi dentro calc(), lo stacco fra due elementi inline. Misurato qui su file reali, compreso ciò che brotli ti avrebbe risparmiato comunque.TutorialCostruire una tabella Markdown da zero, senza contare i trattini a manoLa cosa più piccola che sia ancora una tabella sono due righe: una riga di intestazione e una riga delimitatrice. Ecco perché la seconda è obbligatoria in GitHub Flavored Markdown, dove le tabelle a barre non esistono affatto, e che cosa fa un generatore che scrivere a mano non può fare.GuidaIncollare una tabella in una pull request: che cosa si rompe, e i due caratteri che la romponoUna tabella Markdown vieta esattamente due caratteri dentro una cella: la barra verticale e l'a capo. Ecco che cosa fa ciascuno, come li tratta un convertitore, perché l'escape va applicato nell'ordine giusto, e perché il riempimento non conta mai.GuidaTrasporre una tabella le cui righe avrebbero dovuto essere colonneChe ne è della riga di intestazione, delle righe di lunghezza diversa, dei tipi — e l'unica cosa con cui trasporre viene regolarmente confuso e che non può fare.SpiegazioneDa XML a JSON: attributi, ripetizione e la trappola dell'array a un solo elementoDue documenti che differiscono solo per quanti figli esistono producono due forme JSON diverse, e senza uno schema nessun convertitore può distinguerli. Più ciò che questo fa davvero con attributi, contenuto misto e spazi — e l'unica cosa che continua a non poter registrare.SpiegazioneDa CSV a JSON: i cinque casi che rompono qualsiasi convertitoreDelimitatori tra virgolette, a capo incorporati, tipi ambigui, intestazioni duplicate e codifica. Ogni caso è passato dal convertitore e qui c'è l'output esatto — compresi i due che non salva.

Strumenti correlati

Queste cifre vengono dall'aver eseguito questi strumenti su file veri e compresso il risultato, non da una promessa di un fornitore. Il peso dipende interamente dal file: un foglio di stile scritto con commenti lunghi non si comprime come uno senza, e i tuoi numeri non saranno i nostri. Nemmeno i minificatori si equivalgono — due di questo sito divergono sullo stesso input — quindi tratta qualsiasi output minificato come codice nuovo, da rileggere prima di pubblicare. Tieni l'originale leggibile nel controllo di versione, minifica in fase di build e controlla la pagina in un browser prima di pubblicare.

Fonti

Hai notato un errore in questo articolo?