Datei hochladen
  1. base64hub
  2. Base64 verstehen
  3. Performance von Data-URIs
Performance

Performance von Data-URIs: wann sich eingebettetes Base64 lohnt

Eine Datei als Base64-Data-URI einzubetten spart eine Anfrage und kostet Bytes, Caching und manchmal Renderzeit. Kompression verändert die Rechnung, und bei SVG verändert sie sie anders.

Was eine Data-URI kostet

Eine Data-URI steckt eine Datei in eine URL: data:image/png;base64,iVBORw0KGgo.... Sie lässt sich überall verwenden, wo eine URL stehen kann, ein Icon kann also im src-Attribut im HTML oder in einem CSS-background-image liegen, und der Browser stellt nie eine separate Anfrage dafür.

Die Kehrseiten:

  • Größe. Base64 macht die Nutzdaten 4/3 so groß wie das Original, etwa 33 % größer (die genaue Formel steht in Der Größen-Overhead von Base64). Das Präfix data:image/png;base64, kommt mit weiteren 22 Bytes hinzu.
  • Caching. Die eingebettete Datei wird nur als Teil des Dokuments gecacht, das sie enthält. Ein Logo, das in jede HTML-Seite eingebettet ist, wird mit jeder Seite erneut heruntergeladen. In eine CSS-Datei eingebettet, wird es mit diesem CSS gecacht, und die Änderung eines einzigen Icons macht das ganze Stylesheet ungültig.
  • Rendern. Der Browser kann nichts zeichnen, bevor render-blockierendes CSS angekommen ist. Ein Stylesheet mit 200 KB eingebetteter Schriften oder Bilder verzögert das erste Rendern um die Zeit, die diese Bytes zum Herunterladen brauchen. Im HTML schieben eingebettete Daten den nachfolgenden Inhalt im Bytestrom weiter nach hinten.
  • Kein Lazy Loading. loading="lazy" an einem <img> mit Data-URI spart nichts, denn die Bytes sind bereits mit der Seite angekommen.

Dem steht eine eingesparte Anfrage gegenüber. Unter HTTP/1.1 war das viel wert, da Browser nur eine Handvoll Verbindungen pro Host öffneten. Mit HTTP/2 und HTTP/3 teilen sich viele Anfragen eine Verbindung, die Ersparnis ist also kleiner: im Wesentlichen die Anfrage- und Antwort-Header plus ein Roundtrip Latenz für Dateien, die der Browser spät entdeckt.

Gemessen: was gzip und Brotli mit Base64 machen

Die 33 % gelten für unkomprimierten Text. Die meisten HTML- und CSS-Dateien werden mit gzip oder Brotli ausgeliefert, entscheidend ist also die komprimierte Größe. Wir haben sie selbst gemessen.

Methode. Beispieldateien aus Debian-13-Paketen: ein PNG-Icon mit 16×16 (Icon-Theme HighContrast), ein RGBA-PNG mit 48×48 (Theme hicolor), das blaue Xfce-Hintergrundbild als JPEG mit 2880×1800, ein daraus mit Pillow bei Qualität 80 auf 800×500 verkleinertes JPEG, die Schrift Roboto Slab Regular als WOFF2 und zwei SVG-Icons (ein symbolisches Adwaita-Icon mit 479 Bytes und der GNOME-Debian-Swirl mit 7,6 KB). Jede Datei und ihre Base64-Kodierung (nur die Nutzdaten, ohne das Präfix data:) wurde mit zlib aus Node.js 24 komprimiert: gzip auf Stufe 9 und Brotli mit Qualität 11, die typischen Einstellungen für vorkomprimierte statische Dateien. Größen in Bytes.

DateiRohBase64Roh gzipBase64 gzipRoh BrotliBase64 Brotli
PNG 16×16281376285306285284
PNG 48×484.5526.0724.5754.6024.5514.589
JPEG 800×5008.19510.9287.4257.1737.1606.908
JPEG 2880×1800197.011262.684182.684183.945180.114181.140
WOFF2-Schrift52.53270.04452.53852.76552.53652.690
SVG-Icon479640291427247410
SVG-Swirl7.61010.1483.1234.3982.5823.823

Was die Zahlen zeigen:

Bereits komprimierte Binärdateien verlieren fast den ganzen Overhead. PNG-, JPEG- und WOFF2-Daten sind schon komprimiert und nahezu zufällig, erneutes Komprimieren bringt daher wenig (beide PNGs wurden mit gzip sogar etwas größer). Base64 von Zufallsbytes verwendet 64 Symbole mit je 8 Bit, und ein Huffman-Coder bringt das auf rund 6 Bit pro Symbol zurück. Komprimiertes Base64 landete zwischen 96 % und 107 % der komprimierten Binärdatei und zwischen 84 % und 109 % der Rohdatei. Die JPEGs hier waren selbst noch leicht komprimierbar, deshalb fielen ihre Base64-Versionen sogar etwas kleiner aus als das gzip-komprimierte JPEG; der Unterschied ist zu klein, um damit zu planen. Beim winzigen PNG mit 16×16 fallen die festen 18 Bytes für Header und Trailer von gzip prozentual stark ins Gewicht, und Brotlis schlankere Rahmenstruktur hat sie beseitigt.

SVG wird schlechter. SVG ist Text mit vielen Wiederholungen, und Kompression liebt das: Der Swirl schrumpfte mit gzip von 7.610 auf 3.123 Bytes. Base64 verteilt jede 3-Byte-Gruppe auf 4 Zeichen, deren Werte von der Ausrichtung abhängen, ein wiederholter Teilstring sieht also nicht mehr zweimal gleich aus. Gzip-komprimiertes Base64-SVG war 41–47 % größer als gzip-komprimiertes SVG, mit Brotli 48–66 % größer.

URL-kodiertes SVG vs. Base64

SVG braucht überhaupt kein Base64, denn es ist bereits Text. Eine URL-kodierte Data-URI hält es lesbar:

.flag {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 0v16h2V8h3l1 2h5V2h-4L9 0z'/%3E%3C/svg%3E");
}

Mindestens zu maskieren sind %, # (es würde ein URL-Fragment einleiten), < und >, dazu das Anführungszeichen, das das Attribut begrenzt. Wer im SVG doppelte gegen einfache Anführungszeichen tauscht, muss diese nicht maskieren. Nicht-ASCII-Zeichen müssen als UTF-8 prozentkodiert werden.

Dieselben zwei SVGs, auf dieselbe Weise gemessen:

SVGKodierungGrößegzipBrotli
IconBase64640427410
IconMinimale URL-Kodierung493293253
IconencodeURIComponent723326279
SwirlBase6410.1484.3983.823
SwirlMinimale URL-Kodierung7.1793.0572.549
SwirlencodeURIComponent11.5943.3192.750

„Minimal“ heißt: Leerraum zusammengefasst, doppelte Anführungszeichen durch einfache ersetzt und nur %, #, <, > maskiert. Das ließ sich etwa auf die Größe des Original-SVG komprimieren; der Swirl ist sogar etwas kleiner, weil das Zusammenfassen von Leerraum Bytes entfernt hat. Vollständiges encodeURIComponent ist unkomprimiert größer, lässt sich aber immer noch weit besser komprimieren als Base64. Das Tool SVG in Data-URI erzeugt beide Formen nebeneinander.

Base64 ist für SVG weiterhin sinnvoll, wenn ein Tool oder eine API nur Base64 akzeptiert oder wenn das SVG Zeichen enthält, über deren Maskierung Sie lieber nicht nachdenken möchten.

Content Security Policy und data:

Unter einer Content Security Policy umfasst 'self' keine data:-URLs. Jede Direktive, die sie erlauben soll, muss das Schema aufführen:

Content-Security-Policy: default-src 'self'; img-src 'self' data:; font-src 'self' data:

data: in img-src und font-src zu erlauben ist verbreitet und risikoarm. In script-src, default-src oder object-src ist es etwas ganz anderes: Ein Angreifer, der Markup einschleusen kann, kann dann ein Skript liefern, ohne einen externen Host zu brauchen, und das untergräbt einen Großteil des Sinns von CSP. Wenn eingebettete Bilder an Ihrer Richtlinie scheitern, erweitern Sie nur img-src.

Browser hindern Seiten außerdem daran, das oberste Fenster zu einer data:-URL zu navigieren, ob per Link, Weiterleitung oder Skript. Eine Data-URI lässt sich also in eine Seite einbetten, aber nicht als Link auf oberster Ebene öffnen.

Wann sich das Einbetten lohnt

Lohnt sich meist:

  • Winzige Icons und UI-Grafiken unter etwa 1–2 KB, besonders solche, die für das erste Rendern gebraucht werden. Der Overhead der Anfrage ist ein großer Teil ihrer Größe, und die Kompression beseitigt den Großteil der Base64-Kosten.
  • HTML in einer einzigen Datei. Offline-Berichte, exportierte Dokumentation, Testabdeckungsseiten und HTML-Vorschauen von E-Mails, die auch direkt von der Festplatte geöffnet funktionieren müssen.
  • Kritisches CSS, das ohnehin ins HTML eingebettet wird und ein kleines Hintergrundbild gleich mitnimmt.
  • Generierte Inhalte wie ein Diagramm, das ein Skript als PNG rendert und in einen HTML-Bericht einbettet.

Lohnt sich meist nicht:

  • Fotos und alles über ein paar Kilobyte. Sie sind als separate Dateien mit langer Cache-Dauer besser aufgehoben.
  • Bilder, die auf vielen Seiten vorkommen und in jeder HTML-Antwort erneut heruntergeladen würden.
  • Webfonts. Eine WOFF2-Datei hat typischerweise einige zehn Kilobyte (die oben gemessene 52 KB), eingebettet ins CSS blockiert das Stylesheet das Rendern länger, und separate Schriftdateien lassen sich cachen und vorladen.
  • Alles unterhalb des sichtbaren Bereichs. Eine separate Datei mit loading="lazy" kostet nichts, bis sie gebraucht wird.

E-Mail ist ein Fall für sich. Die Unterstützung für data:-Bilder unterscheidet sich zwischen Mailprogrammen, testen Sie also in den Programmen, die Ihre Empfänger tatsächlich verwenden. Der verlässliche Weg, ein Bild in eine HTML-E-Mail einzubetten, ist ein Inline-MIME-Anhang, auf den mit cid: verwiesen wird; das ist ebenfalls Base64, nur innerhalb der MIME-Struktur. Siehe Base64 in E-Mails.

Data-URI aus einem Bild erstellen

Legen Sie ein PNG, JPEG, WebP oder SVG ab und erhalten Sie die Data-URI samt Größe. Die Datei bleibt in Ihrem Browser.

Bild in Base64

Häufige Fragen

Sind Base64-Bilder langsamer als normale Bilder?

Nicht grundsätzlich. Kleine eingebettete Bilder sparen eine Anfrage, große blähen dagegen HTML oder CSS auf, lassen sich nicht separat cachen und können das Rendern verzögern. Unter ein paar Kilobyte hilft das Einbetten, darüber schadet es.

Beseitigt gzip den Base64-Overhead von 33 %?

Bei PNG, JPEG und WOFF2 fast vollständig: In unseren Messungen lag das gzip-komprimierte Base64 nur wenige Prozent neben der Binärdatei. Bei SVG und anderem Text nicht, dort war gzip-komprimiertes Base64-SVG 41–47 % größer als gzip-komprimiertes SVG.

Was ist für eingebettetes SVG besser, URL-Kodierung oder Base64?

URL-Kodierung. Sie bleibt lesbar und bearbeitbar und lässt sich etwa so gut komprimieren wie das Original-SVG. Maskieren Sie mindestens #, %, < und >, und verwenden Sie im SVG einfache Anführungszeichen, wenn das Attribut doppelte verwendet.

Warum blockiert die Content Security Policy meine Data-URI-Bilder?

CSP behandelt data: als eigenes Schema, das 'self' nicht abdeckt. Ergänzen Sie data: in img-src (oder font-src für Schriften). Fügen Sie es nicht zu script-src oder default-src hinzu.

Weiterlesen