Skip to content

Data URI vs Base64 SVG: Which Encoding to Use in CSS

If you inline SVG in CSS, you have two encoding options: percent-encoding (URL-encoding) and Base64. Both produce a valid data: URI. They differ in size, readability, and tooling compatibility. For most icons, URL-encoding wins on bytes. Base64 still has a place.

The math

Base64 is fixed-rate. Every 3 input bytes become 4 output characters. That is a flat 33.3% overhead, plus the data:image/svg+xml;base64, prefix (26 bytes). It is deterministic: a 1 KB SVG becomes ~1.37 KB encoded, regardless of contents.

URL-encoding is variable-rate. Safe characters pass through as 1 byte. Reserved characters (<, >, #, %, ") expand to 3 bytes (%3C, %3E, etc.). SVG is mostly ASCII letters, digits, and whitespace — all safe. The reserved set is dominated by <, >, ", and # (in hex colors).

For a typical icon SVG, reserved characters make up 3–12% of the source. So URL-encoding adds 3–12% overhead vs Base64's flat 33%.

A practical note: you do not need to encode every reserved character. In CSS url() contexts, you really only need to escape <, >, #, and %, and optionally swap " for '. Tools like SVG Encoder do this minimally.

Real example

Source SVG (231 bytes):

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#0ea5e9" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12l5 5L20 7"/></svg>

URL-encoded (244 bytes payload, 5.6% overhead):

background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230ea5e9' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12l5 5L20 7'/%3E%3C/svg%3E");

Base64 (308 bytes payload, 33.3% overhead):

background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMGVhNWU5IiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBhdGggZD0iTTUgMTIgbDUgNUwyMCA3Ii8+PC9zdmc+");
EncodingPayload sizevs raw
Raw SVG231 B
URL-encoded244 B+5.6%
Base64308 B+33.3%

For this icon, URL-encoding saves 64 bytes (21%) over Base64. Multiply by every icon in your CSS bundle, then by every cache miss, and it adds up.

After gzip the gap narrows but does not close. Base64 compresses poorly because the alphabet destroys byte patterns from the original markup. URL-encoded SVG retains its repetitive XML structure, which gzip handles well.

When to use which

Use URL-encoding for:

  • Icon sets, UI chrome, decorative shapes — anything that is primarily paths and basic attributes.
  • Anywhere you might want to read or diff the output. URL-encoded SVG is mostly legible.
  • CSS background-image, mask-image, border-image, list-style-image, cursor.

Use Base64 for:

  • SVGs containing embedded raster images (<image href="data:image/png;base64,…">). The inner Base64 payload contains characters that would need heavy percent-escaping; double-encoding inflates size and risks tooling errors.
  • Build pipelines or CMS fields that mangle %, #, or unescaped quotes. Some markdown processors, PostCSS plugins, and CSS-in-JS libraries do not round-trip URL-encoded data URIs cleanly.
  • HTML img src and link rel="icon", where Base64 is the conventional choice and tooling is battle-tested.

Default to URL-encoding. Fall back to Base64 only when something downstream breaks.

Generate both at once

Hand-encoding is error-prone — forget to escape # in a fill color and your CSS silently fails. Paste your SVG into SVG Encoder to get both encodings, live byte counts, a “Smaller” indicator, and ready-to-paste output for CSS background-image, mask-image, HTML img, and JSX.

Further reading