SVG as a CSS Background Image: Data URIs Done Right
SVG Nexus · Last updated: November 2026
A CSS background cannot point at inline markup, so the SVG has to travel inside a URL as an encoded data URI. The encoding is where everyone trips: escape the # characters, mind the quotes, keep the viewBox — and solve recoloring with masks instead of fill.
When a background is the right tool
Backgrounds are for decoration that repeats or sits behind content: subtle patterns, the icon inside a pseudo-element, a checkmark fused into a custom checkbox. The moment an image carries meaning, it belongs in an <img> or inline, where it can have alt text and be styled directly. Backgrounds have no accessibility tree presence at all, so keep them purely visual and never let one be the only carrier of information.
Encoding: the rules that break everyone
A data URI is the file, escaped into a URL: url("data:image/svg+xml,..."). Three rules decide whether it renders. First, every # becomes %23 — colors are full of hex values, and a raw # ends the URL at that point, silently truncating the image. Second, quote discipline: wrap the URL in double quotes and use single quotes inside the SVG, or the string breaks. Third, the embedded SVG must keep its viewBox (and explicit width/height), because a background has no other way to know the artwork's intrinsic proportions. Base64 encoding sidesteps all escaping, at roughly a third more bytes; UTF-8 with careful escaping is smaller and still readable. Minify the SVG first — whitespace and comments are payload here.
Size and position it like an image
Once encoded, it behaves like any background image: background-size takes contain, cover, or exact lengths (a square icon usually wants its rendered size, e.g. 20px), background-position centers it, and background-repeat defaults to tiling — set no-repeat unless the tiling is the point. Because the SVG carries its own viewBox, contain-like behavior stays crisp at every device pixel ratio.
Recoloring: stop fighting fill, use a mask
A background SVG cannot hear your stylesheet: its fills were frozen into the URL. Per-theme variants mean re-encoding the file with different hex values — workable for two themes, miserable for five. The modern alternative is to not ship the color at all: use the SVG as a mask-image over a plain background-color. The element paints background: currentColor (or any theme variable), and -webkit-mask / mask with the same data URI clips it to the icon's shape. One asset, every state and theme, hover transitions on the color included. Keep the plain background version as the fallback where mask support is a concern.
Producing the string
Hand-escaping is how %23 bugs are born; generate the declaration. Converters — including this site's SVG-to-CSS tool — take an icon's code and emit the encoded background (and mask) form, so the workflow is: pick the icon, copy its SVG from its page, convert, paste. The underlying SVG in this catalog keeps its viewBox and namespaced IDs, so the pasted result keeps scaling exactly like the original.
.icon-mask {
width: 1.25rem;
height: 1.25rem;
background-color: currentColor;
-webkit-mask: url("/icon-library-assets/lucide/lucide-search.svg") center / contain no-repeat;
mask: url("/icon-library-assets/lucide/lucide-search.svg") center / contain no-repeat;
}
Verified facts about this site
- Export formats: Optimized SVG, PNG, WebP, React TSX, Vue 3 SFC, Svelte, CSS mask or data URI, SVG sprite
- Raster export sizes: 64px, 128px, 256px, 512px, 1024px, 2048px
- Workspace upload cap per file: 2 MB
- License and author are documented on every icon page.