Embedding images as Base64 data URLs in CSS and HTML

Published: 2026-09-05

How data URLs pack image bytes into CSS and HTML, why Base64 inflates size by about 33%, when embeds beat external files, and how to encode images locally without uploading them.

Data URLs let you put an image inside a stylesheet or HTML document instead of pointing at a separate file. The browser still needs the same pixels—it just reads them from a long data:… string rather than fetching /logo.png. That is handy for tiny icons, email HTML, and self-contained demos, and painful when the string is huge or cached poorly.

This guide covers the data: URL shape, how Base64 relates to raw bytes, CSS and HTML snippets, size trade-offs, and when to keep a normal file instead.

Anatomy of a data URL

A typical image data URL looks like:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…
Part Role
data: Scheme that says “the resource is inline”
image/png MIME type of the payload
;base64 Declares that the payload is Base64-encoded bytes
, then payload Encoded image bytes (no separate HTTP body)

Without ;base64, some data URLs use percent-encoding of text (useful for tiny SVG or HTML snippets). For raster images and most binary formats, Base64 is the practical choice.

MIME must match the real format: image/jpeg, image/png, image/webp, image/gif, image/svg+xml, and so on. A wrong label can make the browser refuse to decode the image even if the Base64 is correct.

Base64 in one minute

Base64 represents binary as ASCII characters (A–Z, a–z, 0–9, +, /, with = padding). Every 3 input bytes become 4 output characters—about a 33% size increase before you even add the data:mime;base64, prefix.

That inflation matters:

  • A 12 KB PNG becomes roughly 16 KB of Base64 characters, plus a short prefix for the full data URL.
  • HTML/CSS that embeds many images pays that tax per embed, and the document itself grows.

Related byte views: Hex encoding (two hex digits per byte, ~100% expansion) and the planned Base64-vs-hex tooling under encoding utilities. For images you care about MIME + Base64, not hex dumps.

CSS: background-image

.icon {
  background-image: url("data:image/png;base64,iVBORw0KGgo…");
  background-size: contain;
  background-repeat: no-repeat;
}

Notes:

  • Prefer double quotes around the URL; Base64 can include + and /, which are fine inside a quoted url().
  • Keep embeds small (icons, dots, simple logos). Large photo backgrounds belong in separate files so CSS stays cacheable and readable.
  • Multiple layers still work: background-image: url("data:…"), linear-gradient(…).

HTML: <img> and beyond

<img
  src="data:image/webp;base64,UklGRiQAAABXRUJQVlA4…"
  alt="Product badge"
  width="64"
  height="64"
/>

You can also use data URLs in:

  • Inline SVG <image href="data:…"> (mind SVG’s own escaping rules)
  • Some email HTML templates (clients vary; test thoroughly)
  • Canvas / JS when you need a string source without a network request

Always set meaningful alt text for content images. Decorative CSS backgrounds do not need alt; decorative <img> embeds should use empty alt="" only when they add no information.

When embeds help vs hurt

Prefer a data URL when… Prefer a normal file / CDN when…
Asset is a few KB (icons, badges, sparklines) Photos, hero images, or anything above a few dozen KB
You need a single self-contained HTML/CSS snippet You want browser caching and parallel downloads
Offline demos, email prototypes, or docs with no asset pipeline Production pages where LCP and cache hit rates matter
Avoiding an extra request for one tiny critical icon Many images—each embed bloats HTML/CSS and blocks parsing

Large data URLs can also hit practical length limits if you paste them into address bars, some proxies, or older tooling. Treat them as document content, not as shareable links.

Workflow tip: compress and resize first (Lossy vs lossless image compression, Image Optimizer), then Base64. Encoding a 2 MB photo into a stylesheet is almost always the wrong order of operations.

SVG as data URLs

SVG can be embedded as data:image/svg+xml;base64,… like any other image type, or sometimes as UTF-8 with percent-encoding (no Base64). Base64 is simpler for copy-paste from a file; raw SVG-in-URL needs careful escaping of #, ", and newlines.

For icons that stay as markup in React or HTML, converting to a component (SVG to React) or minifying paths (SVG Minifier) often beats a Base64 blob—you keep accessibility hooks and CSS currentColor more easily.

Encode locally (privacy)

Online “image to Base64” sites often upload the file to encode it. Product shots, unpublished creatives, and anything with EXIF/GPS should not take that trip if you can avoid it. Browser APIs such as FileReader.readAsDataURL encode in the tab—same local-only model as other developer utilities (Why “local only” matters for developer tools).

You get the MIME from the file (or from sniffing), the Base64 payload, and ready-made CSS/<img> snippets without a server round-trip.

Try it on LocalTools

Open Image to Base64:

  1. Drop one image (PNG, JPEG, WebP, GIF, BMP, SVG — max 8 MB).
  2. Check MIME type, dimensions, and size vs original (Base64 and full data URL estimates).
  3. Switch output mode: data URL, raw Base64, CSS background-image, or HTML <img>.
  4. Copy or download the text—encoding stays in your browser via FileReader.

Prefer optimizing large assets first, then embed only what must travel inside HTML or CSS.

Related reading

All learn articles