Zum Inhalt springen
Allin

Verschönern oder minifizieren: wofür beides gut ist und was es am Gewicht ändert

Veröffentlicht am 10.8.2026 · 13 Min. Lesezeit · Entwickler-Tools

Daniel Okonkwo

Daniel OkonkwoFront-end-Entwickler und Tech-Redakteur bei Allin

Web-Performance · Dateiformate

Anhand von 4 Quellen geprüft

Profil ansehen
Kurz gesagt

Verschönern ist zum Lesen da, Minifizieren zum Ausliefern. Das Gewichtsargument ist weit schwächer, als die rohe Bytezahl vermuten lässt, denn alles, was du ausliefert, wird gegzippt, und gzip kümmert sich bereits um Wiederholung — und Einrückung ist der wiederholteste Text überhaupt. Vier Stylesheets liefen durch diesen Minifier, beide Größen notiert. Eine handgeschriebene Karten-Komponente ging von 1 612 auf 1 118 Bytes, ein Schnitt von 30,6 %; gegzippt von 659 auf 555, eine Ersparnis von 104 Bytes. Die eigentliche Lehre steckt darin, die beiden Durchgänge zu trennen. Bei denselben vier Dateien sparte allein das Entfernen von Leerraum 48, 103, 104 und 147 komprimierte Bytes — rund hundert, egal ob 1,6 kB oder 22 kB. Allein das Entfernen der Kommentare sparte 57, 1 358, 2 420 und 1 042. Bei einer stark kommentierten Datei machen die Kommentare 96 % der echten Ersparnis aus; der Leerraum ist ein Rundungsfehler. Minifiziere also wegen der Kommentare und des toten Codes, nicht wegen der Zeilenumbrüche — und nie auf Kosten der Richtigkeit. Dieser Minifier besteht aus fünf regulären Ausdrücken und zerlegt fünf Dinge: Er löscht den Leerraum, den CSS beidseits des + in calc() verlangt, sodass calc(100% + 16px) zu einer ungültigen Deklaration wird, die der Browser verwirft; er verändert das Innere von Strings und macht aus content: "a; b" ein "a;b"; er löscht einen String, der bloß wie ein Kommentar aussieht; er verschluckt eine Kommentarsequenz in einer Data-URI; und er schreibt a[title="hello, world"] um. Dieselbe Seite bietet css-compressor, einen Scanner, der keines davon zerlegt und bei einer 22 746 Bytes großen Datei 2 Bytes größer ausfällt.

Vier echte Stylesheets durch den Minifier, roh und nach gzip gemessen. Alle Leerzeichen zu entfernen sparte 48, 103, 104 und 147 komprimierte Bytes; die Kommentare zu entfernen 57, 1 358, 2 420 und 1 042. Dazu die fünf Eingaben, an denen dieser Minifier scheitert.

Die Messung, die die meisten Artikel auslassen: nach gzip

Ein Minifier meldet die rohe Bytezahl, weil das die einzige ist, die er ausrechnen kann. Es ist nicht die, die unterwegs ist. Jedes über HTTP ausgelieferte Stylesheet kommt komprimiert an, und die beiden Vorgänge überschneiden sich: gzip kodiert eine Folge wiederholter Bytes als kurze Rückverweisung, und vier Leerzeichen Einrückung, dreihundertmal wiederholt, sind das Billigste, was es je zu sehen bekommt. Diese Einrückung vor dem Komprimieren zu entfernen, nimmt gzip Arbeit ab, die es umsonst erledigt hat.

Also wurden die beiden Durchgänge getrennt und jeder für sich gemessen. Nur Kommentare entfernen, dann nur Leerraum, dann beides — bei vier Dateien: einer handgeschriebenen Karten-Komponente von 1 612 Bytes und drei Stylesheets direkt aus dem Repository dieser Seite. Mit gzip Stufe 9 komprimiert, sparte der Leerraum-Durchgang 48, 103, 104 und 147 Bytes. Keine Prozente — Bytes, und ungefähr dieselben hundert, ob die Datei 1,6 kB oder 22 kB groß war, denn in einem Stylesheet gibt es nur begrenzt viele verschiedene Einrückungen, wie lang es auch wird. Der Kommentar-Durchgang sparte bei denselben vier Dateien 57, 1 358, 2 420 und 1 042 komprimierte Bytes.

Eine Datei genügt als Beleg. Die globals.css dieser Seite ist 7 148 Bytes groß, ein großer Teil davon Prosa darüber, warum welche Farbe gewählt wurde. Leerraum zu entfernen brachte sie von 3 140 gegzippten Bytes auf 3 036 — 104 Bytes, 3,3 %. Die Kommentare zu entfernen brachte sie auf 720, eine Ersparnis von 2 420 Bytes, 77 %. Sechsundneunzig Prozent des echten Gewinns kamen aus den Kommentaren und nichts aus den Zeilenumbrüchen. Das ist das ganze Argument in einer Datei: Minifiziere, um zu entfernen, was der Browser nicht brauchen kann, nicht, um zu entfernen, was der Kompressor ohnehin erledigt.

Verschönern kostet komprimiert fast nichts

Die Symmetrie gilt in beide Richtungen, und das ist der brauchbare Teil. Das Beispiel des HTML-Verschönerers ist eine minifizierte Seite von 485 Bytes. Mit zwei Leerzeichen Einrückung verschönert wird sie 627 Bytes groß — 142 mehr, ein Zuwachs von 29,3 %, die Zahl, die Leute nervös macht. Gegzippt geht sie von 343 auf 369 Bytes: 26 Bytes, 7,6 %. Sechsundzwanzig Bytes sind nichts. Wenn du eine lesbare Seite aus gutem Grund ausliefert — ein Dokumentationsbeispiel, eine E-Mail-Vorlage, die jemand bearbeiten muss, eine Seite, deren Quelltext man ansehen können soll —, sind die komprimierten Kosten der Lesbarkeit geringer als eine Favicon-Anfrage.

Der HTML-Verschönerer lohnt auch dafür, dass man versteht, was er nicht tut. Er übernimmt den Inhalt von pre und textarea Byte für Byte, weil deren Leerraum gerendert wird. Er behält ein einzelnes Leerzeichen zwischen zwei Inline-Elementen, weil dessen Entfernen zwei Wörter auf dem Bildschirm zusammenklebt. Und er lässt ein zitiertes Attribut in Ruhe, sodass title="a > b" unversehrt bleibt, statt an der spitzen Klammer abgeschnitten zu werden. Alle drei Verhaltensweisen wurden direkt geprüft und alle drei halten.

Einen blinden Fleck hat er allerdings, und zwar genau den, den sein eigener Kommentar geschlossen zu haben behauptet. Zwei durch ein Leerzeichen getrennte Buttons — <div><button>A</button> <button>B</button></div> — kommen aus dem Minifier als <button>A</button><button>B</button> zurück. Buttons sind inline-block, dieses Leerzeichen wird also gezeichnet, und der Abstand zwischen den beiden Buttons verschwindet. Die angewandte Regel lautet, Leerraum zwischen zwei Block-Tags sei unsichtbar, und die Liste der Inline-Elemente enthält a, b, span, code und zwei Dutzend weitere, aber nicht button, nicht select und kein Bild in einem Link. Prüfe jede Buttonreihe nach dem Minifizieren.

Fünf Eingaben, die dieser CSS-Minifier falsch behandelt

Die Seite css-minifier besteht aus fünf regulären Ausdrücken: Kommentare entfernen, Leerraumfolgen auf ein Leerzeichen reduzieren, die Leerzeichen um eine Reihe von Satzzeichen entfernen, ein Semikolon vor einer schließenden Klammer entfernen, trimmen. Das reicht für ein Stylesheet, das du vor einer Stunde selbst geschrieben hast, und für nichts sonst, denn ein regulärer Ausdruck kann Struktur nicht von Inhalt unterscheiden.

Der erste Fehlschlag ist der ernste. CSS Values and Units Level 3 sagt in der Syntax von calc(), dass beidseits der Operatoren + und - Leerraum erforderlich ist. Die Satzzeichenliste enthält hier das +, also wird aus calc(100% + 16px) ein calc(100%+16px), und die ganze Deklaration ist ungültig: Der Browser verwirft sie und fällt auf das zurück, was vorher galt. Da das - nicht in der Liste steht, überlebt calc(100% - 16px) unversehrt, was schlimmer ist — die Hälfte deiner calc-Ausdrücke funktioniert, die andere verschwindet stillschweigend. Das ist kein erfundener Fall. Die Datei apps/web/components/app/app-shell.module.css in diesem Repository enthält calc(74px + env(safe-area-inset-bottom)), den Abstand, der die mobile Tab-Leiste vom Home-Indikator freihält. Lauf sie durch dieses Werkzeug, und dieser Abstand ist weg.

Die anderen vier haben dieselbe Wurzel: Strings und Data-URIs sind Inhalt, und die Durchgänge behandeln sie als Struktur. Aus content: "a; b" wird content:"a;b", weil das Semikolon auf der Satzzeichenliste steht. Aus content: "{ }" wird content:"{}". Aus a[title="hello, world"] wird a[title="hello,world"], und der Selektor trifft nicht mehr. Ein Stylesheet, dessen content-String die Zeichen enthält, die einen CSS-Kommentar öffnen und schließen — content: "/* not a comment */" —, kommt als content:"" zurück, der String geleert. Und ein Hintergrundbild als Data-URI, das zufällig dieselbe Zweizeichenfolge enthält, verliert alles dazwischen: url("data:image/svg+xml,...%3E/*x*/%3C...") kommt mit gelöschter Mitte an, das Bild tot.

Zwei Dinge, die er nicht zerlegt, der Ausgewogenheit halber. Benutzerdefinierte Eigenschaften überleben: --shadow: 0 2px 8px rgba(0, 0, 0, 0.1) kommt als --shadow:0 2px 8px rgba(0,0,0,0.1) heraus, derselbe Wert. Media Queries überleben ebenfalls: @media screen and (min-width: 600px) wird @media screen and (min-width:600px), weiterhin gültig, und die moderne Bereichssyntax @media (400px <= width <= 700px) bleibt unangetastet, weil <= nicht auf der Satzzeichenliste steht.

Zwei Minifier auf derselben Seite, und der sichere ist 2 Bytes größer

Die Seite css-compressor benutzt eine andere Engine. Statt Muster abzugleichen, läuft sie Zeichen für Zeichen durch die Datei und markiert jedes Zeichen als Struktur oder Literal — alles innerhalb eines Strings, eines Kommentars oder eines Klammerpaars ist Literal, und keine Transformation darf es anfassen. Dieses eine Kennzeichen hält eine Data-URI, einen calc()-Ausdruck und die Dezimalstellen eines rgba() unversehrt.

Der ganze Sinn des naiven Ansatzes sollte darin bestehen, kleiner zu sein. Er ist es nicht. Beide liefen über dieselben drei echten Stylesheets. Bei app-shell.module.css, 22 746 Bytes Eingabe, lieferte die Regex-Fassung 19 278 Bytes und der Scanner 19 280 — 2 Bytes Unterschied, und gegzippt war der Scanner sogar 1 Byte kleiner, 4 191 gegen 4 192. Bei admin.css betrug die Lücke 1 Byte roh und 2 Bytes gegzippt. Bei globals.css 8 Bytes roh. Acht Bytes, bei einer Datei, in der die sichere Fassung das Leerzeichen in @media (min-width: 600px) und in rgba(0, 0, 0, 0.1) behält. Es gibt überhaupt kein Größenargument für die Regex-Fassung; sie ist schlicht diejenige, die die Datei gelegentlich zerstört.

SVG ist die Ausnahme — und hat seinen eigenen Fehler

Alles bisher Gesagte lautet, das Gewichtsargument fürs Minifizieren sei schwach. Bei SVG ist es stark, denn das Gewicht eines exportierten SVG besteht gar nicht aus Leerraum. Eine kleine Zeichnung aus einem Vektoreditor schleppt eine XML-Deklaration mit, einen Editor-Kommentar, einen Titel, eine Beschreibung, einen RDF-Metadatenblock, eine benannte Ansicht mit der letzten Zoomstufe, zwei Editor-Namensräume, eine Identitätsmatrix als Transformation, eine Strichstärke und eine Deckkraft auf ihren eigenen Standardwerten sowie Koordinaten mit sieben Nachkommastellen. Lauf so eine Datei — 1 071 Bytes — durch svg-optimizer, und sie kommt mit 256 Bytes heraus, ein Schnitt von 76,1 %. Gegzippt: von 603 auf 207, ein Schnitt von 65,7 %. Diese Ersparnis ist echt, weil das Entfernte einmaliger Text ist, und einmaliger Text ist genau das, wobei ein Kompressor nicht helfen kann.

Derselbe Durchlauf brachte einen Fehler zutage, den man kennen sollte, bevor man das Werkzeug benutzt. Farben durchlaufen zwei Schritte in der falschen Reihenfolge: Sie werden zuerst gekürzt und dann an den Zahlenrundungs-Durchgang übergeben, der Hexziffern als Zahlen liest. stroke="#000000" wird zu #000 gekürzt und dann zu #0 gerundet. black wird #0. red wird #f0. Und weil das Zahlenmuster wissenschaftliche Schreibweise akzeptiert, explodiert eine Hexfarbe, deren Ziffern ein e einrahmen: #e5e7eb kommt als #e50000000eb heraus, #1e293b als #1e+293b, #0e7490 als #0. Derselbe Durchgang schreibt url(#g-0010) zu url(#g-10) um und lässt id="g-0010" unangetastet, sodass der referenzierte Verlauf verschwindet. All das wurde in einem echten Browser mit den Standardeinstellungen reproduziert. Die Option zum Runden von Zahlen abzuschalten verhindert jeden dieser Fälle, um den Preis einiger Bytes Genauigkeit.

Zwei weitere Punkte zum selben Werkzeug. Es entfernt title und desc als Editor-Metadaten — das sind aber die beiden Elemente, die ein Screenreader für ein SVG vorliest, sodass ein zugängliches Icon es nicht mehr ist. Seine Prüfung auf fehlerhaftes Markup dagegen ist von der sorgfältigen Sorte: Ein Browser meldet einen XML-Fehler, indem er ein Element namens parsererror einpfropft, und allein nach diesem Namen zu suchen würde jede gültige Zeichnung ablehnen, die selbst eines trägt. Das Werkzeug fragt stattdessen die Engine — einmal je Sitzung parst es etwas absichtlich Kaputtes, liest den Namensraum der zurückkommenden Markierung und schaut fortan nur noch dort nach. Eine Zeichnung mit einem parsererror-Element wird ganz normal optimiert; ein nicht geschlossenes Tag wird weiterhin abgelehnt.

Die beiden Durchgänge getrennt gemessen an vier echten Dateien, rohe Bytes und gzip Stufe 9
DateiOriginal, roh / gzipNur Leerraum, gzip gespartNur Kommentare, gzip gespart
Handgeschriebene Karten-Komponente1 612 / 65948 Bytes57 Bytes
app-shell.module.css (dicht, wenige Kommentare)22 746 / 5 661103 Bytes1 358 Bytes
globals.css (stark kommentiert)7 148 / 3 140104 Bytes2 420 Bytes
admin.css4 767 / 1 855147 Bytes1 042 Bytes
Aus einem Editor exportiertes SVG, kompletter Optimierer1 071 / 603Metadaten, kein Leerraum396 Bytes, 65,7 %
CSS-MinifiziererVerkleinere CSS, indem du Kommentare und unnötige Leerzeichen entfernst.Tool ausprobieren

Häufige Fragen

Lohnt Minifizieren von CSS noch, wenn der Server ohnehin alles gzippt?
Ja, aber wegen der Kommentare, nicht wegen der Leerzeichen. Bei den vier hier gemessenen Dateien sparte das Entfernen aller Leerzeichen und Zeilenumbrüche 48, 103, 104 und 147 gegzippte Bytes — jeweils rund hundert Bytes, egal ob die Datei 1,6 kB oder 22 kB groß war, weil gzip wiederholte Einrückung fast umsonst kodiert. Das Entfernen der Kommentare sparte bei denselben Dateien 57, 1 358, 2 420 und 1 042 gegzippte Bytes. Ist dein Stylesheet dokumentiert, sind die Kommentare die ganze Ersparnis; ist es das nicht, bringt Minifizieren etwa ein Zehntel Kilobyte, und die Mühe wäre in einem Durchgang gegen ungenutztes CSS besser aufgehoben. Wofür Minifizieren in einer Build-Pipeline wirklich taugt: Es kommt zusammen mit den Durchgängen, auf die es ankommt — Regeln entfernen, die nichts auf der Seite benutzt, doppelte Deklarationen zusammenführen, Farben und Einheiten kürzen.
Mein Layout ist nach dem Minifizieren kaputt. Wo schaue ich zuerst?
Suche im minifizierten File nach calc( und lies jedes davon. Enthält eines ein Pluszeichen ohne Leerzeichen drumherum — calc(100%+16px) —, ist diese Deklaration ungültig und der Browser ignoriert sie. CSS verlangt beidseits von + und - in calc() Leerraum, und ein Regex-Minifier, der die Abstände um Satzzeichen strafft, löscht ihn. Suche als Nächstes nach content: und nach jedem Attributselektor mit einem Komma oder Semikolon, denn ein naiver Minifier verändert das Innere von Strings. Sieh dann die Data-URIs an: Enthielt eine die beiden Zeichen, die einen CSS-Kommentar öffnen, und später die beiden, die ihn schließen, ist alles dazwischen entfernt. Vergleiche schließlich die Zahl der Regeln vorher und nachher; ist sie gesunken, ging Strukturelles verloren, nicht bloß Leerraum.
Sollte ich eine minifizierte Datei, die ich nicht geschrieben habe, vor dem Bearbeiten verschönern?
Ja, und das ist die ehrliche Verwendung eines Verschönerers. Neuformatieren ändert nur Leerraum, kann also das Verhalten nicht verändern, und macht aus einer einzeiligen Datei etwas, das ein Diff beschreiben kann. Zwei Einschränkungen. Erstens ist eine verschönerte Datei nicht automatisch eine Quelldatei — wurde das Original aus Sass, TypeScript oder einer Komponentenbibliothek erzeugt, verschwindet deine Änderung an der Ausgabe beim nächsten Build. Zweitens ist Verschönern und erneutes Minifizieren nicht immer die Identität: Bei der hier getesteten HTML-Engine fügt ein Hin und Zurück je ein Leerzeichen vor und nach dem Text jedes Nicht-Inline-Elements ein, wodurch eine 133-Byte-Seite auf 145 Bytes wächst und dann stabil bleibt. Im Browser harmlos, aber erwarte keine byteidentische Datei zurück.
Warum spart der SVG-Optimierer so viel mehr als der CSS-Minifier?
Weil er anderes Material entfernt. Ein CSS-Minifier entfernt Leerraum und Kommentare; um den Leerraum kümmert sich der Kompressor bereits, also zählen nur die Kommentare. Ein SVG-Optimierer entfernt Editor-Metadaten, Standardattribute, leere Gruppen und überflüssige Nachkommastellen — alles einmaliger Text, den ein Kompressor nicht zusammenfalten kann. In der hier gemessenen Datei wurden aus 1 071 Bytes roh 256, und aus 603 gegzippten Bytes 207, ein Schnitt von 65,7 %, der die Kompression fast unversehrt überstand. Die Lehre lässt sich verallgemeinern: Jeder Minifier, der bloß neu formatiert, enttäuscht nach gzip, und jeder, der Inhalt löscht, nicht. Genau deshalb ist das Löschen von Inhalt der Teil, den man prüfen muss.
Unterscheidet sich Brotli genug von gzip, um die Antwort zu ändern?
Nein, es macht sie geringfügig stärker. Das Karten-Stylesheet komprimierte mit Brotli auf 527 Bytes gegenüber 659 mit gzip, und minifiziert erreichte es 451 gegenüber 555. Die absolute Ersparnis durchs Minifizieren betrug unter Brotli 76 Bytes und unter gzip 104: Ein besserer Kompressor lässt dem Minifier weniger zu entfernen übrig, genau wie zu erwarten, da beide dieselbe Redundanz beseitigen. Liefert dein Hoster also Brotli aus — die meisten CDNs tun das —, ist das Argument fürs Minifizieren von Leerraum noch schwächer, und das fürs Entfernen von Kommentaren unverändert, denn ein Kommentar ist unter beiden Algorithmen einmaliger Text.

Artikel, die dich interessieren könnten

Alle Ratgeber
RatgeberWas ein Minifier entfernen darf und was nichtMinifizierung muss die Bedeutung erhalten, und interessant ist der Leerraum, der Bedeutung trägt: der Nachfahrenkombinator, die Leerzeichen in calc(), der Abstand zwischen zwei Inline-Elementen. Hier an echten Dateien gemessen, samt dem, was Brotli ohnehin gespart hätte.AnleitungEine Markdown-Tabelle von Grund auf bauen, ohne Striche zu zählenDas Kleinste, das noch eine Tabelle ist, sind zwei Zeilen: eine Kopfzeile und eine Trennzeile. Hier steht, warum die zweite in GitHub Flavored Markdown Pflicht ist, wo Pipe-Tabellen überhaupt nicht existieren, und was ein Generator kann, was Tippen von Hand nicht kann.RatgeberEine Tabelle in einen Pull Request einfügen: was kaputtgeht und die zwei Zeichen, die es kaputtmachenEine Markdown-Tabelle verbietet in einer Zelle genau zwei Zeichen: den Pipe und den Zeilenumbruch. Hier steht, was jedes davon anrichtet, wie ein Konverter damit umgeht, warum das Escape in der richtigen Reihenfolge angewandt werden muss, und warum das Auffüllen nie zählt.RatgeberEine Tabelle transponieren, deren Zeilen Spalten hätten sein sollenWas aus der Kopfzeile wird, was aus ungleich langen Zeilen wird, was aus Typen wird — und die eine Sache, mit der Transponieren regelmäßig verwechselt wird und die es nicht kann.ErklärungXML zu JSON: Attribute, Wiederholung und die Falle des einelementigen ArraysZwei Dokumente, die sich nur in der Zahl der Kinder unterscheiden, ergeben zwei verschiedene JSON-Formen, und ohne Schema kann kein Konverter sie auseinanderhalten. Dazu, was dieser wirklich mit Attributen, gemischtem Inhalt und Leerraum macht — und das Einzige, was er weiterhin nicht festhalten kann.ErklärungCSV zu JSON: die fünf Fälle, an denen jeder Konverter scheitertTrennzeichen in Anführungszeichen, eingebettete Zeilenumbrüche, mehrdeutige Typen, doppelte Spaltennamen und Kodierung. Jeder Fall lief durch den Konverter, und die exakte Ausgabe steht hier — auch die beiden, die er nicht rettet.

Ähnliche Tools

Diese Zahlen stammen daraus, dass diese Werkzeuge auf echte Dateien angewendet und die Ergebnisse komprimiert wurden — nicht aus einem Herstellerversprechen. Das Gewicht hängt vollständig von der Datei ab: Ein Stylesheet mit langen Kommentaren komprimiert anders als eines ohne, und deine Zahlen werden nicht unsere sein. Auch Minifier sind nicht gleichwertig — zwei auf dieser Seite widersprechen sich bei derselben Eingabe —, also behandle jede minifizierte Ausgabe als neuen Code, der vor dem Ausliefern angesehen werden muss. Behalte das lesbare Original in der Versionsverwaltung, minifiziere beim Build und prüfe die Seite im Browser, bevor du veröffentlichst.

Quellen

Hast du einen Fehler in diesem Artikel entdeckt?