Skip to content

Instantly share code, notes, and snippets.

@jennyknuth
Last active September 23, 2024 19:12
Show Gist options
  • Save jennyknuth/222825e315d45a738ed9d6e04c7a88d0 to your computer and use it in GitHub Desktop.
Save jennyknuth/222825e315d45a738ed9d6e04c7a88d0 to your computer and use it in GitHub Desktop.
Transform an SVG into a data URI—best practice

How to transform an SVG into a data URI

by Jenny Knuth, based on the work of Chris Coyier and Taylor Hunt

A data URI is a nice way to include a web resource without needing to make an HTTP request. Chris Coyier explains the technique nicely in Probably Don't Base64 SVG.

While a PNG might use Base64 encoding, for SVG, there is a better way.

Taylor Hunt's experiments led to this solution for optimizing SVGs in data URIs:

"So the best way of encoding SVG in a data URI is data:image/svg+xml,[actual data]. We don’t need the ;charset=utf-8 parameter (or the invalid ;utf8 parameter…), because URLs are always ASCII."

Here is a step-by-step method to create your encoded SVG string to include as a data URI:

  1. Run your SVG file through svgo to optimize. (Directions are found at the svgo link.)

  2. In your text editor, replace all double quotes in your SVG file with single quotes. Make sure there are no line breaks.

  3. Replace all non-ASCII and URL-unsafe characters by running your SVG string through an encoding function like the one below by Taylor Hunt—surround your svgString with double quotes in the function's argument.

  4. Paste your encoded SVG into your HTML tag's src attribute or CSS's url call using double quotes, after the data:image/sg+xml, prefix.

Examples:

HTML:

<img src="data:image/svg+xml,%3Csvg width='247' height='34' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23FFF' fill-rule='non.zero'%3E%3Cpath d='M13.918 ... 4.022-2.888 4.57V26h-4.46V7.975z' fill='%23D7DCE1'/%3E%3C/g%3E%3C/svg%3E"/>

CSS:

.logo {
  background: url("data:image/svg+xml,%3Csvg ... /svg%3E");
}

The %3svg starts your encoded string and the svg%3E ends your encoded string.

Let me know if any questions.

// this function is from the work of Taylor Hunt found at https://codepen.io/tigt/post/optimizing-svgs-in-data-uris
function encodeSvg(svgString) {
return svgString.replace('<svg',(~svgString.indexOf('xmlns')?'<svg':'<svg xmlns="http://www.w3.org/2000/svg"'))
//
// Encode (may need a few extra replacements)
//
.replace(/"/g, '\'')
.replace(/%/g, '%25')
.replace(/#/g, '%23')
.replace(/{/g, '%7B')
.replace(/}/g, '%7D')
.replace(/</g, '%3C')
.replace(/>/g, '%3E')
.replace(/\s+/g,' ')
//
// The maybe list (add on documented fail)
//
// .replace(/&/g, '%26')
// .replace('|', '%7C')
// .replace('[', '%5B')
// .replace(']', '%5D')
// .replace('^', '%5E')
// .replace('`', '%60')
// .replace(';', '%3B')
// .replace('?', '%3F')
// .replace(':', '%3A')
// .replace('@', '%40')
// .replace('=', '%3D')
;}
@jonesmac
Copy link

jonesmac commented Nov 1, 2023

Has anyone had any luck using the svg-in-data-uri technique with an svg that has nested <image> elements?

Take this one. I cannot get the external images to load when the svg is used as a data-uri in an img src.

<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1200 1200"><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/background/2.png"/><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/body/0-2.png"/><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/cloth/4.png"/><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/hand/0-2-4.png"/><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/head/0-2.png"/><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/mouth/0-2-2.png"/><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/nose/0-2-0.png"/><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/eyes/0-2-1.png"/><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/hair/0.png"/></svg>

@siaikin
Copy link

siaikin commented Mar 19, 2024

Has anyone had any luck using the svg-in-data-uri technique with an svg that has nested <image> elements?有没有人运气好地将 svg-in-data-uri 技术与嵌套了 <image> 元素的 svg 一起使用?

Take this one. I cannot get the external images to load when the svg is used as a data-uri in an img src.拿这个。当 svg 在 img src 中用作数据 uri 时,我无法加载外部图像。

<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1200 1200"><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/background/2.png"/><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/body/0-2.png"/><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/cloth/4.png"/><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/hand/0-2-4.png"/><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/head/0-2.png"/><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/mouth/0-2-2.png"/><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/nose/0-2-0.png"/><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/eyes/0-2-1.png"/><image href="https://neotokyo.mypinata.cloud/ipfs/QmeqeBpsYTuJL8AZhY9fGBeTj9QuvMVqaZeRWFnjA24QEE/hair/0.png"/></svg>

@jonesmac I have the same problem, I am going to convert the image to dataurl inline into svg. If you have any solutions please holler.

@jonesmac
Copy link

@siaikin I think the issue is that datat uri's have "unique opaque origins" by modern browsers. See - https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs

Data URLs are treated as unique opaque origins by modern browsers, rather than inheriting the origin of the settings object responsible for the navigation.

Since they don't seem to inherit from the settings object responsible for navigation, it means the urls inside data uri's aren't 'navigated to' and therefore no images render. 🤷

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment