14

Backstory:

  • Goal: create a triangular shadow that can be applied via CSS and is scale-independant (i.e. a vector, not a raster image)
  • After much research (tho I'm certainly open to alternatives) I chose to use an SVG background image as a data uri (to avoid the extra HTTP request).
  • I know that this can work: http://jsfiddle.net/6WAtQ/

Where I'm stuck:

  • I created a simple svg triangle, with a Gaussian blur effect, if it's written directly in the HTML (as opposed to the CSS) the svg works perfectly: http://jsfiddle.net/RAKWB/
<svg class="shadow" xmlns="http://www.w3.org/2000/svg" version="1.1">
  <defs>
    <filter id="f1">
      <feGaussianBlur in="SourceGraphic" stdDeviation="5" />
    </filter>
  </defs>
  <polygon points="200,0 200,200 0,200" filter="url(#f1)"/>
</svg>​
body {
  background-image: url("data:image/svg+xml;utf8,data:image/svg+xml;utf8,<svg class="shadow" xmlns="http://www.w3.org/2000/svg" version="1.1"><defs><filter id="f1"><feGaussianBlur in="SourceGraphic" stdDeviation="5" /></filter></defs><polygon points="200,0 200,200 0,200" filter="url(%23f1)"/></svg>");
}

Thoughts?

jon
  • 5,961
  • 8
  • 35
  • 43

3 Answers3

17

See how the working fiddle has double quotes just inside the url() and then all the SVG content uses single quotes? You need to do the same. Otherwise the parser doesn't know where the url content ends.

Alternatively you could make the url use single quotes and keep your SVG content the same.

body { background-image: url('data:image/svg+xml;utf8,<svg class="shadow" xmlns="http://www.w3.org/2000/svg" version="1.1"><defs><filter id="f1"><feGaussianBlur in="SourceGraphic" stdDeviation="5" /></filter></defs><polygon points="200,0 200,200 0,200" filter="url(%23f1)"/></svg>'); }
Nathan Arthur
  • 8,287
  • 7
  • 55
  • 80
Robert Longson
  • 118,664
  • 26
  • 252
  • 242
  • Also works directly on an IMG src by replacing just 4 characters in the SVG string: ``IMG.src='data:image/svg+xml;utf8,'+SVG.replace(/"/g, "'").replace(//g, "%3e").replace(/#/g, "%23");`` – Danny '365CSI' Engelman Feb 21 '20 at 15:20
  • Sadly, not every browser support "clear" svg syntax in data uri (ex: Chrome) you have to escape it with encodeURIComponent. But it's no more human readable, with a minimal character set escaped you can "more or less" read it and modify it inplace... You can use a simple line of code as @danny commented above. However, escaping double quotes is not necessary if you encapsulate the result in a simple quoted `url('data:...')`. – Thomas Di G Feb 24 '21 at 18:49
  • Here is the transformer (es6): `const svg2css = svg=> "url('data:image/svg+xml;utf8,"+svg.replace(/\n/g, "").replace(//g, "%3e").replace(/#/g, "%23") + "')" ` – Thomas Di G Feb 24 '21 at 18:50
  • to use it : `$0.style.backgroundImage = svg2css("")` – Thomas Di G Feb 24 '21 at 18:52
5

You can also use a base64 encoding for a cleaner format, even if it increase the actual SVG file size. See also css-tricks.com post.

i.e.:

background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIy NCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij4KICAgIDxwYXRoIGQ9 Ik0wIDBoMjR2MjRoLTI0eiIgZmlsbD0ibm9uZSIvPgogICAgPHBhdGggZD0iTTEw LjA5IDE1LjU5bDEuNDEgMS40MSA1LTUtNS01LTEuNDEgMS40MSAyLjU4IDIuNTlo LTkuNjd2Mmg5LjY3bC0yLjU4IDIuNTl6bTguOTEtMTIuNTloLTE0Yy0xLjExIDAt MiAuOS0yIDJ2NGgydi00aDE0djE0aC0xNHYtNGgtMnY0YzAgMS4xLjg5IDIgMiAy aDE0YzEuMSAwIDItLjkgMi0ydi0xNGMwLTEuMS0uOS0yLTItMnoiLz4KPC9zdmc+ Cg==');

You can use this bash command (tested on MacOS X) to easily generate the CSS background property:

echo "background: url('data:image/svg+xml;base64,"$(openssl base64 < Downloads/material-design-icons-1.0.0/action/svg/ic_exit_to_app_24px.svg)"');"
araks
  • 40,738
  • 8
  • 34
  • 39
3

Make sure to use percent-encoding in data URI not encoded with base64.

For example, for an SVG, encode like this:

body { 
  background-image: url('data:image/svg+xml;utf8,%3Csvg%20class%3D%22shadow%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%3E%3Cpolygon%20style%3D%22stroke%3A%23252423%3Bfill%3A%23252423%3B%22%20points%3D%220%2C200%200%2C0%20200%2C0%22%2F%3E%3C%2Fsvg%3E'); 
}

This is equivalent to the following SVG:

<svg class="shadow" xmlns="http://www.w3.org/2000/svg" version="1.1"><polygon style="stroke:#252423;fill:#252423;" points="0,200 0,0 200,0"/></svg>

To percent encode an image, you can use the following JavaScript code:

console.log(encodeURIComponent('<svg class="shadow" xmlns="http://www.w3.org/2000/svg" version="1.1"><polygon style="stroke:#252423;fill:#252423;" points="0,200 0,0 200,0"/></svg>'))
kiewic
  • 15,852
  • 13
  • 78
  • 101