SVG to CSS Encoder
Encode an SVG into a url() data URI for background-image, mask-image or a custom property — url-encoded, xmlns-checked, entirely on this device.
The quote you pick is the delimiter of the CSS string inside url(), so that character is percent-encoded in the payload and the attribute delimiters in the markup use the other one. An SVG referenced from CSS is fetched and parsed as XML, so without xmlns it renders nothing; adding it is reported as a note either way. url() is always quoted here, so a literal space is legal and stays readable; encoding it as %20 costs two characters per space and is only needed if you paste the URI somewhere unquoted.
The thumbnail is a neutralized copy rendered as an image; the URI below is encoded from the exact markup you pasted, byte for byte.
Size
| SVG bytes carried | 112 B |
|---|---|
| URI characters | 145 |
| Base64 URI would be | 178 |
| Difference | -33 (-18.5%) |
This page measures the Base64 alternative but never emits one; the Data URI Generator is where Base64 data URIs are produced.
Escapes
| Character | Becomes | Count | Why |
|---|---|---|---|
| < | %3C | 3 | Safety |
| > | %3E | 3 | Safety |
| # | %23 | 1 | Required |
- This <svg> has no width or height attribute — it has no intrinsic pixel size, so whatever contains it decides how large it is drawn.
.icon {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Ccircle cx='10' cy='10' r='9' fill='%233b82f6'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-size: contain;
}:root {
--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Ccircle cx='10' cy='10' r='9' fill='%233b82f6'/%3E%3C/svg%3E");
}
.icon {
background-image: var(--icon);
}.icon {
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Ccircle cx='10' cy='10' r='9' fill='%233b82f6'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Ccircle cx='10' cy='10' r='9' fill='%233b82f6'/%3E%3C/svg%3E");
mask-size: contain;
mask-repeat: no-repeat;
background-color: currentColor;
}Press ? for shortcuts · Stored only on this device —
Do it offline:$ python3 -c "import sys,urllib.parse as u;print('url(\"data:image/svg+xml,'+u.quote(sys.stdin.read().replace('\"',chr(39)),\"/:=,;'()!\$&*+?~-._ \")+'\")')" < icon.svg
How to use it
- Paste the markup, drop a .svg file on the source pane, or pick one.
- Set the options: the CSS string quote, xmlns insertion, space escaping.
- Read the rule table — a row per escaped character, marked required or safety.
- Copy a snippet: the background-image rule, the custom property, or the mask-image form.
- Glance at the thumbnail and the chips before you paste it anywhere.
Paste SVG markup and take away the url() value a stylesheet can hold: escaped exactly where CSS and the URL parser need it, with the xmlns declaration checked, because markup referenced from CSS is parsed as XML. The size table counts the finished URI against the Base64 form of the same bytes. It all runs in this tab.
How it works
Characters leave in three classes. Required escapes cannot survive as themselves: the percent sign, taken first so escapes already in your markup are never decoded twice; the number sign, which opens a fragment identifier — fetching data:text/plain,a?b#frag resolves to a?b; whichever quote delimits the CSS string; and the control characters, since a CSS string cannot hold a raw line break. Safety escapes are a documented choice: angle brackets and the characters RFC 3986 excludes. The rest is kept — letters, digits, slash, colon, comma, semicolon, question mark, plus, ampersand, parentheses and the space — so the payload stays legible. The circle above spends 7 escapes on 112 bytes.
Two quoting systems meet in one line and only one can own the character. An XML attribute value is wrapped in quotes; so is a CSS string. When both pick the same one the declaration ends early, so attribute delimiters flip to the other quote — at the offsets the parser recorded, not by replacing every quote in the document. A quote inside text content belongs to your drawing, so it becomes %22.
Markup behind url() is fetched and parsed as XML, and XML knows no element names of its own. Without xmlns="http://www.w3.org/2000/svg" on the root the document is well formed and draws nothing — the ordinary reason a URI looks right while the box stays empty. Fragment exports often omit it, so a missing declaration is inserted and chipped; switch that off and the URI still arrives, with a warning. An xlink: prefixed name gets the same treatment for xmlns:xlink.
Examples
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><circle cx="10" cy="10" r="9" fill="#3b82f6"/></svg>.icon {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Ccircle cx='10' cy='10' r='9' fill='%233b82f6'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-size: contain;
}The defaults: attribute delimiters became apostrophes, angle brackets and the hex colour's number sign became escapes, spaces stayed spaces. 145 URI characters against 178 for Base64.
<svg viewBox="0 0 24 24"><path d="M4 12h16" stroke="#111827" stroke-width="2" fill="none"/></svg>data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 12h16' stroke='%23111827' stroke-width='2' fill='none'/%3E%3C/svg%3EA stroke icon out of a design file, with no namespace declaration. It is inserted after the tag name and chipped; path data untouched.
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="20" viewBox="0 0 120 20"><text x="0" y="14" font-size="12">le "café" fermé</text></svg>data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='20' viewBox='0 0 120 20'%3E%3Ctext x='0' y='14' font-size='12'%3Ele %22caf%C3%A9%22 ferm%C3%A9%3C/text%3E%3C/svg%3EQuotes inside the text node become %22 while the delimiters flip, and each é goes out as its two UTF-8 bytes, %C3%A9 — so the URI is plain ASCII.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
The number sign in a hex colour is the usual breakage
fill="#3b82f6" carries the character that cuts a data URI short: from the number sign on is a fragment identifier. It goes out as %23.
A prettified export pays for its indentation
Every line break becomes %0A and every tab %09: a CSS string cannot span raw lines, and nothing is collapsed here.
Single-quote mode is a cost, not a repair
The default CSS string is double-quoted, so apostrophes pass through. Choose the single-quoted string and each becomes %27.
The XML declaration and DOCTYPE are reported, never removed
An editor export often opens with both: 38 bytes and 98 bytes in the SVG 1.1 pairing, escaped like everything else and priced in a chip. SVG Optimizer drops them.
Escaping loses to Base64 on heavy text
Escapes are cheap for ASCII markup and dear for prose. A Japanese label spends nine characters per three-byte character: one such icon measures 242 Base64 characters against 257 escaped.
mask-image needs a colour to show anything
The mask snippet paints background-color: currentColor through the drawing's alpha — that is how an icon follows the text colour. Drop it and the shape is filled with nothing.
Common errors
This <svg> has no xmlns attribute and none was added, so the URI will not render. An SVG referenced from CSS is fetched and parsed as XML, which requires xmlns='http://www.w3.org/2000/svg'.- The insertion is off and the markup has no namespace, so the URI is handed over with the consequence stated.
This markup uses xlink: names, so xmlns:xlink='http://www.w3.org/1999/xlink' was added. An undeclared namespace prefix makes the document ill-formed, and an ill-formed SVG draws nothing.- A chip, not a failure. Older exports reference symbols with xlink:href yet leave the prefix undeclared — which survives in an HTML page and fails in a URI.
This URI is 8528 characters long. CSS sets no limit and nothing was refused, but past about 8192 characters a stylesheet becomes hard to read and to diff.- Nothing is truncated and no browser limit is claimed, because CSS sets none. It is a readability warning: at this size the drawing is better kept in its own .svg file.
Input is larger than the 4 MB limit for this tool. Encode a file that size on your own machine: python3 -c "import sys,urllib.parse as u;print('url(\"data:image/svg+xml,'+u.quote(sys.stdin.read().replace('\"',chr(39)),\"/:=,;'()!\$&*+?~-._ \")+'\")')" < icon.svg- Past four megabytes the paste is declined whole rather than half-encoded; the printed command does the job over a file on disk.
FAQ
Why doesn't my SVG show up in background-image?
Two causes cover nearly all of it: the root has no xmlns attribute, so XML parsing yields elements no renderer recognises; or a hex colour's number sign was left raw, cutting the URI short.
Should I url-encode or Base64 an SVG?
Measure it — the size table does. Markup is mostly characters that cost nothing to escape, so escaping usually wins: 145 characters against 178 for the circle above. Heavy non-ASCII text tips it over. Data URI Generator emits Base64.
Can I recolor the SVG with CSS?
Not through background-image: a referenced image is an isolated document, so fill and stroke inside it never see the page's cascade. Use the mask-image snippet: the drawing becomes a mask and background-color: currentColor supplies the colour.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Encode the current markup again with the options as they stand.
- ⌘/Ctrl + C
- Copies the background-image snippet when nothing is selected; a selection copies as usual.
- ⌘/Ctrl + Shift + C
- Copy the background-image snippet whatever the selection.
- ⌘/Ctrl + S
- Save the snippet as svg-background.css, ahead of the browser's save-page action.
- t
- Switch theme, unless a text field or an IME composition has focus.
- ? or ⌘/Ctrl + /
- Open the help dialog listing these bindings.
- Esc
- Close the help dialog; focus returns to its opener and the markup is never cleared.