Stand: Juli 2026
Der Bildformat-Fall hat das Muster gezeigt: Das CDN verhandelt pro Browser die beste Variante, ohne dass sich URLs ändern oder das Quellsystem angefasst wird. Dasselbe Content-Negotiation-Prinzip funktioniert eine Schicht tiefer — nicht für Bildformate über den Accept-Header, sondern für Kompression über Accept-Encoding: CSS und JavaScript als Brotli in der höchsten Stufe ausliefern.
Warum sich das lohnt, in Zahlen (gemessen an einer echten Shopware-6-Theme-CSS, 366 KB):
- gzip −9: 56,5 KB
- Brotli on-the-fly (Stufe ~5, was Edge oder Origin zur Laufzeit schaffen): 51,8 KB
- Brotli −q 11, vorkomprimiert: 43,4 KB — 23 % kleiner als gzip, rund 15 % kleiner als das On-the-fly-Brotli
Der springende Punkt: Level 11 ist zur Laufzeit unbezahlbar — die Kompression dauert je Datei Sekunden, das macht kein Server pro Request und kein CDN am Edge. CDNs komprimieren on-the-fly auf mittlerem Niveau, und genau deshalb verschenkt die Standard-Einstellung „Compress objects automatically“ die letzten 15 %.
Warum hier Vorkompression richtig ist (und bei Bildern falsch war)
Bei den Bildern verbot sich die Vorab-Konvertierung: sechsstellige Bestände, laufende Importe, mehrere Zielformate. Assets sind das exakte Gegenteil: ein paar hundert Dateien, die sich ausschließlich beim Deployment ändern. Einmal komprimieren pro Deploy, fertig — der teuerste Kompressionslevel kostet dann genau nichts zur Laufzeit.
# Deploy-Hook: beste Kompression, einmalig pro Release
find public/theme -type f \( -name '*.css' -o -name '*.js' \) \
-exec brotli -q 11 -kf {} \; \
-exec gzip -9 -kf {} \;
Die Kette
1. Origin liefert die fertigen Varianten — nginx mit ngx_brotli:
brotli_static on; # nimmt die .br-Datei, wenn der Browser br kann
gzip_static on; # sonst die .gz-Datei
# kein brotli on / gzip on nötig — es wird nichts zur Laufzeit gerechnet
2. Das CDN cached die Varianten getrennt. Bei CloudFront heißt das: eine Cache-Policy, die gzip- und Brotli-Support aktiviert (die Standard-Policy CachingOptimized tut das) — damit wandert das normalisierte Accept-Encoding in den Cache-Schlüssel und jeder Browser bekommt am Edge seine Variante. Das automatische Edge-Komprimieren bleibt aus; das CDN reicht die Origin-Varianten durch.
3. Der Browser merkt nichts — gleiche URL, Content-Encoding: br, nur eben die q-11-Fassung.
Das Ergebnis auf der render-kritischen Theme-CSS ist unmittelbar LCP-wirksam: weniger Bytes auf dem kritischen Pfad, bei null Laufzeit-CPU und null Risiko — schlimmstenfalls fehlt eine .br-Datei und der Browser bekommt gzip, wie bisher.
Die Checkliste
- Deploy-Hook mit
brotli -q 11+gzip -9(atomar mit dem Release ausrollen — Fingerprint-URLs machen das trivial: neue Datei, neue URL) - Origin:
brotli_static+gzip_staticaktiv, Laufzeit-Kompression für Assets aus - CDN-Cache-Policy: gzip und Brotli als Varianten aktiviert, automatische Edge-Kompression für diese Pfade aus
- Kontrolle per
curl:curl -sI -H 'Accept-Encoding: br' <asset-url> | grep -iE 'content-encoding|content-length'— die Länge muss zur.br-Datei passen, nicht zur On-the-fly-Größe - Für das gecachte HTML (das nicht statisch ist) gilt weiter die Varnish-Kette — die beiden ergänzen sich