English

Developer tools · Base64 encoder & decoder

Inline Base64 images in CSS: when data: URIs help and when they hurt

· Why it matters

base64 performance

A CSS stylesheet with inline Base64-encoded SVG icon data: URIs
Original ToolAcre vector illustration

Inlining an image as a Base64 data: URI removes a request but grows the file and defeats caching. This post lays out when the trade is worth it and when a separate file is faster.

The stylesheet that grew to hundreds of kilobytes — one team's inlining habit and how it showed up in load timings

A development team decided that inlining small icons as Base64 data: URIs in their CSS would reduce HTTP requests and improve page load speed. Over time, as more icons were added, the stylesheet grew to 400 kilobytes.

The CSS bundle, which should contain style rules, is now dominated by image data. The team measured load timing and found that the page was slower than before the inlining, not faster. The problem became clear: the 400-kilobyte stylesheet is downloaded on every page load and cached per page, whereas if the icons were separate files, a single icon file would be cached and shared across every page.

What a data: URI inlines and why it is Base64 — the syntax, the media type and the size penalty

Adding more pages to the site made the problem worse, since each page downloads the same stylesheet with all those inlined images again. This post explains what a data: URI is, why it is Base64, how inlining affects caching and performance, and the rules of thumb for deciding when the trade-off is worth it. A data: URL is a way to embed a resource directly in an HTML or CSS file instead of linking to an external file. The syntax is data:mediaType;base64,encoded_bytes.

The mediaType declares what kind of resource follows, such as image/svg+xml for SVG, image/png for PNG, or text/plain for text. The ;base64 flag indicates that the payload is Base64-encoded rather than percent-encoded text. The encoded_bytes are the actual data. When a browser encounters a data: URL in an href, src or background-image property, it decodes the Base64 and renders the resource inline. No HTTP request happens because the resource is already there, embedded in the parent document. This saves one or a few HTTP requests, which matters in an HTTP/1.1 world where each request has overhead.

Caching and the critical path — why inlined bytes are downloaded again with every page that includes the stylesheet

In an HTTP/2 or HTTP/3 world where many requests can be multiplexed over one connection, the savings are smaller. The size penalty of Base64 encoding is immediate and significant. An SVG icon that is 3 kilobytes when saved as an XML file becomes 4 kilobytes when Base64-encoded and embedded as a data: URI. The 33% size increase from encoding must be added to every page that includes the stylesheet. If the icon is used on ten pages, the stylesheet is downloaded ten times, each time including that same 4-kilobyte encoded image.

If the icon were a separate file, the 3-kilobyte original would be downloaded once and cached, then used from cache on all ten pages. The economic choice is clear for most icons: separate files are smaller overall. The inlining benefit applies only when an icon is used on exactly one page or very few pages, and the icon is genuinely critical to that page. A favicon that appears on every page is a poor candidate for inlining; it is better as a separate cached file.

Parsing costs on the client — how large inline strings are handled by CSS and HTML parsers, described qualitatively

A one-off illustration used only on a landing page might benefit from inlining to save a request. Caching defeats most of the benefits of inlining data: URIs in stylesheets. A stylesheet is typically cached for days or weeks. When the stylesheet is downloaded, every resource inlined in it is downloaded again, even if the browser already has that image cached. If the stylesheet is updated, all the inlined data must be revalidated or re-downloaded, even if only one CSS rule was changed.

This causes bloat: changes to colors or spacing trigger a full re-download of the stylesheet, including kilobytes of image data that did not change. A separate image file can be cached independently with its own expiration headers, updated separately and reused across stylesheets and pages. The browser cache is far more efficient when resources are separate files than when they are embedded in larger documents. Parsing and rendering costs compound when large Base64 strings are embedded in stylesheets. A CSS parser must read the entire stylesheet before applying rules.

Worked example: inlining a small SVG icon as text — pasting the markup into the encoder and assembling the data: URI by hand

A 400-kilobyte stylesheet with inlined Base64 is 400 kilobytes of text that must be parsed before any rules can be applied. An HTML parser rendering a page with a large data: URI in a style attribute or a background-image property must decode the Base64 and construct the image before the element can render. For simple SVG icons this is trivial. For more complex images or larger icons, the decoding and rendering happen on the main thread, potentially blocking interactivity. The qualitative cost is real but hard to measure without profiling.

As a rule, if the inlined image is anything larger than a few kilobytes, separate files are faster. A worked example shows the exact trade-off. Take a simple SVG arrow icon, 1.2 kilobytes of XML. Base64-encoded it becomes 1600 characters, or about 1.6 kilobytes with the data: URL prefix. A separate CSS rule with background-image: url(/icons/arrow.svg) adds maybe 40 bytes to the stylesheet. The icon file is downloaded once, cached and reused. Inlining saves one HTTP request for that one icon but adds 1.6 kilobytes to every stylesheet load.

Rules of thumb that hold up — tiny, critical, single-use assets inline; everything else as a file

If the stylesheet is 50 kilobytes and shared across 20 pages, inlining that icon grows the total download by 32 kilobytes per site visit. The HTTP request it saves is a few hundred bytes of overhead at most. The request is also automatically multiplexed in HTTP/2, eliminating the overhead difference. The inlining trade loses badly unless the stylesheet is tiny, the icon is huge or the icon appears on exactly one page and nowhere else. Rules of thumb that survive scrutiny are limited and specific.

Tiny, critical, single-use assets can be inlined. A 200-byte SVG arrow that appears only on one unusual page might be inlined to save the request overhead. Everything else should be separate. Critical rendering path logic matters: if an icon must be visible immediately and every millisecond of load time costs conversion, inlining might win. For typical pages with typical icons, separate files are almost always better. Test both approaches with your actual assets and measure page load, cache hit rates and request waterfall.

What this does not cover — HTTP/2 and HTTP/3 multiplexing details and image-format compression

Do not assume inlining is an optimization without measurement. The easiest way to end up with a bloated stylesheet is to inline incrementally without measuring whether each addition is actually faster. Base64 encoder & decoder helps you make this decision before committing to inlining. Paste your SVG markup or other icon source into the tool as text. Click Encode and set the options to generate a data: URI. The tool shows you the exact length of the data: URL. Compare that to the size of a separate CSS rule and the asset file itself.

Calculate how many pages would need to share the stylesheet to break even on inlining versus separate files. Assemble the data: URI and test it in an actual HTML page before you commit it to the stylesheet. If the URI is longer than a few hundred characters, the cost of embedding is likely greater than the benefit of saving a request. Use the tool to test your actual icons and assets, then measure the impact on your real page load metrics before and after inlining.

Takeaway: inline sparingly and measure — how the Base64 encoder & decoder lets you encode SVG markup and see the exact size before you commit

The performant approach is to be selective about inlining. Icons used on every page or across many pages are separate cached files. Icons used on exactly one page or truly critical to first paint can be inlined. Measure the trade-off for your actual assets and pages rather than following generic advice. Use Base64 encoder & decoder to see the exact size of any inlined asset before you add it to a stylesheet. The size penalty is real and multiplies across every page view.

Caching and request multiplexing have made the original benefit of inlining less important. For most modern applications, smaller stylesheets and better cache efficiency from separate files outweigh the request overhead. Inline sparingly, measure the result and trust measurement over intuition.