How to Base64 Encode an Image for CSS and HTML
Instead of linking to an external image file, you can embed the image data directly in your CSS or HTML using a Base64 data URI. This eliminates the separate HTTP request for the image — useful for small icons, inline SVGs, and email templates where external requests are blocked.
What a data URI looks like
data:[mime-type];base64,[base64-encoded-data]
A real example for a small PNG:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==
That 1×1 transparent PNG is 68 bytes. Its Base64 data URI is 88 characters — about 30% larger, which is the standard overhead for Base64 encoding.
Using a Base64 image in CSS
/* Background image */
.icon {
background-image: url('data:image/png;base64,iVBORw0KGgo...');
width: 16px;
height: 16px;
background-size: contain;
}
/* As a list-style image */
li {
list-style-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucy...');
}
Using a Base64 image in HTML
<!-- img tag -->
<img src="data:image/jpeg;base64,/9j/4AAQSkZJRgAB..." alt="Photo">
<!-- HTML email (inline images often blocked) -->
<img src="data:image/png;base64,iVBORw0KGgo..." width="200" height="100" alt="Logo">
Generating the data URI in Python
import base64
from pathlib import Path
def image_to_data_uri(path: str) -> str:
mime_map = {
".png": "image/png",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".gif": "image/gif",
".svg": "image/svg+xml",
".webp": "image/webp",
}
suffix = Path(path).suffix.lower()
mime = mime_map.get(suffix, "image/png")
with open(path, "rb") as f:
encoded = base64.b64encode(f.read()).decode("utf-8")
return f"data:{mime};base64,{encoded}"
# Usage
uri = image_to_data_uri("logo.png")
print(f"background-image: url('{uri}');")
Generating the data URI in JavaScript (browser)
// From a File object (e.g. file input)
function fileToDataUri(file) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = (e) => resolve(e.target.result);
reader.readAsDataURL(file);
});
}
// Usage with file input
document.querySelector('input[type="file"]').addEventListener('change', async (e) => {
const uri = await fileToDataUri(e.target.files[0]);
document.querySelector('img').src = uri;
});
SVG: a special case
SVG images can be embedded without Base64 — you can inline the SVG XML directly with URL encoding, which is often smaller:
/* Base64 (larger) */
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucy...');
/* URL-encoded SVG (smaller for simple SVGs) */
background-image: url('data:image/svg+xml,%3Csvg xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22...');
/* Or inline directly in HTML */
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">...</svg>
For SVGs with complex paths, Base64 tends to be smaller. For simple icons (under ~500 bytes), URL-encoding wins.
When to use data URIs
Good use cases:
- Small icons and logos (under ~4 KB) in CSS — saves an HTTP request, the data is usually cached with the stylesheet.
- HTML email — many email clients block external image requests; embedding is the only reliable option.
- Single-file deliverables — HTML reports, exported documents, self-contained demos.
- Favicons — a common pattern for dynamically generated favicons.
When not to use data URIs:
- Large images — a 200 KB photo becomes a 267 KB Base64 string, and it can't be cached independently from the HTML/CSS file.
- Images reused on multiple pages — an external file cached by the browser is faster than re-embedding on each page.
- Performance-critical pages — large data URIs block HTML parsing and increase initial payload size.
Size impact
| Image size | Base64 size | Overhead |
|---|---|---|
| 1 KB | 1.37 KB | +37% |
| 10 KB | 13.7 KB | +37% |
| 100 KB | 137 KB | +37% |
The 33–37% overhead is constant. For anything above 4–5 KB, an external file with proper caching headers is usually faster.
Key takeaways
- Data URI format:
data:[mime];base64,[data]— works insrc,background-image, and anywhere a URL is accepted. - Use Python's
base64.b64encode()orFileReader.readAsDataURL()in browsers to generate them. - Best for small images (under ~4 KB) and HTML email where external requests are blocked.
- SVGs can be URL-encoded instead of Base64-encoded — often smaller for simple icons.
- Base64 adds ~37% overhead — don't embed large images this way.