Base64 images and data URLs: how and when to use them
A data URL puts the image itself inside the HTML or CSS, so there is no separate file to download. That is handy for tiny icons and a trap for anything bigger.
The format
data:[media type][;base64],<data>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==" alt="">
.icon { background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'...%3E"); }
The first example is a complete 1×1 pixel PNG. Without ;base64 the data is read as URL-encoded text, which is how the SVG in the second line works.
How to make one
- In the browser: the Base64 tool accepts a file and gives you the Base64 text without uploading it anywhere. Put
data:image/png;base64,(or the right type) in front. - Linux shell:
printf 'data:image/png;base64,%s' "$(base64 -w 0 icon.png)". The-w 0stops line wrapping, which would break the URL. On macOS usebase64 -i icon.png, which does not wrap. - JavaScript:
FileReader.readAsDataURL(file)returns the whole data URL, type included. For a canvas,canvas.toDataURL("image/png"). - Python:
"data:image/png;base64," + base64.b64encode(open("icon.png","rb").read()).decode()
The real cost
- About 33% bigger. Every 3 bytes become 4 characters. Compression in transit wins some of that back, but not all.
- No caching of its own. The image is part of the page or stylesheet, so it is downloaded again whenever that file changes, and the same icon used on two pages is sent twice.
- It blocks rendering. A large data URL in CSS delays the whole stylesheet, and everything waits for it. A normal image file loads in parallel and can be lazy-loaded.
- It is noisy. Diffs, HTML source and dev tools fill up with unreadable text.
Rule of thumb: inline images under about 2 KB that every page needs (a logo mark, a tiny icon, a placeholder), and serve everything else as a file. With HTTP/2 and HTTP/3, extra small requests are cheap, so the old reason for inlining everything has mostly gone.
SVG: skip Base64
SVG is already text, so Base64 only makes it bigger. URL-encode it instead: replace # with %23, < and > with %3C and %3E, and use single quotes inside the SVG so the CSS can use double quotes around it. The URL encoder does the escaping. The result is usually around a quarter smaller than the Base64 version.
Where data URLs do not work
- Email: many mail clients, including Gmail, do not show
data:images. Attach the image and reference it withcid:, or link to a hosted file. - Content Security Policy: a strict CSP blocks them unless
img-srcincludesdata:. - Address bar: browsers block pages from navigating the top-level window to a
data:URL, because it was used for phishing. Opening one in an<img>is fine. - Wrong media type: a JPEG labelled
image/pngusually still works, but SVG must beimage/svg+xmlor it will not render.
Not sure what a long string is? Paste it into What is this?: it recognises data URLs and plain Base64 and tells you the file type from the first bytes.
Related
QR code not scanning / error correction
Questions
How much bigger is a Base64 image?
About 33%: every 3 bytes become 4 characters, plus the short data: prefix. A 30 KB PNG becomes roughly 40 KB of text.
Are data URL images cached?
Only as part of the HTML or CSS file that contains them. They cannot be cached or shared between pages on their own.
Should I Base64 encode SVG?
Usually not. URL-encoding the SVG text is smaller and still readable; Base64 adds about a third.
Is there a size limit for data URLs?
Modern browsers accept data URLs of many megabytes in images, but very large ones are slow to parse and bloat the page. Keep them to small images.
Published .