Inline SVG in CSS

Is it possible to use an inline SVG definition in CSS?

I mean something like:

.my-class {
  background-image: <svg>...</svg>;
}

If “inline” SVG just isn’t your jam (remember it does have some legit drawbacks like being hard to cache), you can link to an SVG file and retain the ability to affect its parts with CSS by using <object>. <object type="image/svg+xml" data="kiwi.svg" class="logo"> Kiwi Logo <!-- fallback image in CSS --> </object>.

A little late, but if any of you have been going crazy trying to use inline SVG as a background, the escaping suggestions above do not quite work. For one, it does not work in IE, and depending on the content of your SVG the technique will cause trouble in other browsers, like FF.

If you base64 encode the svg (not the entire url, just the svg tag and its contents! ) it works in all browsers. Here is the same jsfiddle example in base64: http://jsfiddle.net/vPA9z/3/

The CSS now looks like this:

body { background-image: 
    url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PGxpbmVhckdyYWRpZW50IGlkPSdncmFkaWVudCc+PHN0b3Agb2Zmc2V0PScxMCUnIHN0b3AtY29sb3I9JyNGMDAnLz48c3RvcCBvZmZzZXQ9JzkwJScgc3RvcC1jb2xvcj0nI2ZjYycvPiA8L2xpbmVhckdyYWRpZW50PjxyZWN0IGZpbGw9J3VybCgjZ3JhZGllbnQpJyB4PScwJyB5PScwJyB3aWR0aD0nMTAwJScgaGVpZ2h0PScxMDAlJy8+PC9zdmc+");

Remember to remove any URL escaping before converting to base64. In other words, the above example showed color='#fcc' converted to color='%23fcc', you should go back to #.

The reason why base64 works better is that it eliminates all the issues with single and double quotes and url escaping

If you are using JS, you can use window.btoa() to produce your base64 svg; and if it doesn't work (it might complain about invalid characters in the string), you can simply use https://www.base64encode.org/.

Example to set a div background:

var mySVG = "<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><linearGradient id='gradient'><stop offset='10%' stop-color='#F00'/><stop offset='90%' stop-color='#fcc'/> </linearGradient><rect fill='url(#gradient)' x='0' y='0' width='100%' height='100%'/></svg>";
var mySVG64 = window.btoa(mySVG);
document.getElementById('myDiv').style.backgroundImage = "url('data:image/svg+xml;base64," + mySVG64 + "')";
html, body, #myDiv {
  width: 100%;
  height: 100%;
  margin: 0;
}
<div id="myDiv"></div>

Inline SVG can be “styled” in the sense that it already has fills and strokes and whatnot the second you put it on the page. That’s awesome and a totally fine way to use inline SVG. But you can also style inline SVG through CSS, which is kinda awesome because, I imagine for a lot of us, CSS is where we feel powerful and comfortable.

For people who are still struggling, I managed to get this working on all modern browsers IE11 and up.

base64 was no option for me because I wanted to use SASS to generate SVG icons based on any given color. For example: @include svg_icon(heart, #FF0000); This way I can create a certain icon in any color, and only have to embed the SVG shape once in the CSS. (with base64 you'd have to embed the SVG in every single color you want to use)

There are three things you need be aware of:

  1. URL ENCODE YOUR SVG As others have suggested, you need to URL encode your entire SVG string for it to work in IE11. In my case, I left out the color values in fields such as fill="#00FF00" and stroke="#FF0000" and replaced them with a SASS variable fill="#{$color-rgb}" so these can be replaced with the color I want. You can use any online converter to URL encode the rest of the string. You'll end up with an SVG string like this:

    %3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%20494.572%20494.572%27%20width%3D%27512%27%20height%3D%27512%27%3E%0A%20%20%3Cpath%20d%3D%27M257.063%200C127.136%200%2021.808%20105.33%2021.808%20235.266c0%2041.012%2010.535%2079.541%2028.973%20113.104L3.825%20464.586c345%2012.797%2041.813%2012.797%2015.467%200%2029.872-4.721%2041.813-12.797v158.184z%27%20fill%3D%27#{$color-rgb}%27%2F%3E%3C%2Fsvg%3E


  1. OMIT THE UTF8 CHARSET IN THE DATA URL When creating your data URL, you need to leave out the charset for it to work in IE11.

    NOT background-image: url( data:image/svg+xml;utf-8,%3Csvg%2....) BUT background-image: url( data:image/svg+xml,%3Csvg%2....)


  1. USE RGB() INSTEAD OF HEX colors Firefox does not like # in the SVG code. So you need to replace your color hex values with RGB ones.

    NOT fill="#FF0000" BUT fill="rgb(255,0,0)"

In my case I use SASS to convert a given hex to a valid rgb value. As pointed out in the comments, it's best to URL encode your RGB string as well (so comma becomes %2C)

@mixin svg_icon($id, $color) {
   $color-rgb: "rgb(" + red($color) + "%2C" + green($color) + "%2C" + blue($color) + ")";
   @if $id == heart {
      background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%20494.572%20494.572%27%20width%3D%27512%27%20height%3D%27512%27%3E%0A%20%20%3Cpath%20d%3D%27M257.063%200C127.136%200%2021.808%20105.33%2021.808%20235.266c0%204%27%20fill%3D%27#{$color-rgb}%27%2F%3E%3C%2Fsvg%3E');
   }
}

I realize this might not be the best solution for very complex SVG's (inline SVG never is in that case), but for flat icons with only a couple of colors this really works great.

I was able to leave out an entire sprite bitmap and replace it with inline SVG in my CSS, which turned out to only be around 25kb after compression. So it's a great way to limit the amount of requests your site has to do, without bloating your CSS file.

With an inline SVG, you only load what you need, nothing else. This is great for performance, and you can also use CSS to style individual parts of the SVG (stroke or fill!) whereas an icon font can only fill the shapes with a single color.

On Mac/Linux, you can easily convert a SVG file to a base64 encoded value for CSS background attribute with this simple bash command:

echo "background: transparent url('data:image/svg+xml;base64,"$(openssl base64 < path/to/file.svg)"') no-repeat center center;"

Tested on Mac OS X. This way you also avoid the URL escaping mess.

Remember that base64 encoding an SVG file increase its size, see css-tricks.com blog post.

5. SVG can be animated CSS. As mentioned in #2, SVG elements can be styled with CSS. The following example uses CSS animations to transform rotatation and SVG attributes like stroke and fill. In my experience so far, browser support is not as consistent as SMIL or JavaScript. Browser support: Chrome, Firefox, Safari. Internet Explorer does not

I've forked a CodePen demo that had the same problem with embedding inline SVG into CSS. A solution that works with SCSS is to build a simple url-encoding function.

A string replacement function can be created from the built-in str-slice, str-index functions (see css-tricks, thanks to Hugo Giraudel).

Then, just replace %,<,>,",', with the %xxcodes:

@function svg-inline($string){
  $result: str-replace($string, "<svg", "<svg xmlns='http://www.w3.org/2000/svg'");
  $result: str-replace($result, '%', '%25');
  $result: str-replace($result, '"', '%22');
  $result: str-replace($result, "'", '%27');
  $result: str-replace($result, ' ', '%20');
  $result: str-replace($result, '<', '%3C');
  $result: str-replace($result, '>', '%3E');
  @return "data:image/svg+xml;utf8," + $result;
}

$mySVG: svg-inline("<svg>...</svg>");

html {
  height: 100vh;
  background: url($mySVG) 50% no-repeat;
}

There is also a image-inline helper function available in Compass, but since it is not supported in CodePen, this solution might probably be useful.

Demo on CodePen: http://codepen.io/terabaud/details/PZdaJo/

Jun 10, 2020 SVG has its own set of elements, attributes and properties to the extent that inline SVG code can get long and complex. By leveraging CSS and some of the forthcoming features of the SVG 2 specification, we can reduce that code for cleaner markup.

but how can I set a background image to an inline svg symbol? *(as below) * My svg is at the top of my web page body and not in an external file. I want .test background image to be the #Icon-Menu symbol.

CSS CSS Reference CSS Browser Support CSS Selector Reference Bootstrap 3 Reference Bootstrap 4 Reference W3.CSS Reference your browser does not support inline SVG.

Using inline SVG allows you to set the fill, which cascades to all the elements within the SVG, or you can fill each element separately if needed. SVG Symbol / Use There is such thing as an SVG sprite, which is a group of SVGs turned into <symbol> elements such that any given icon can be referenced easily with a <use> element.

Comments
  • What are you trying to do, add the image "source" to the style sheet ?
  • Beware that proposed solutions won't work for CSS images, HTML <img> tags and other cases if the SVG is a mix of several images (unless embedded), see background image SVG with mask using external image not working, and specifically restrictions on SVG used as an image.
  • The only browser in which it seems to work nicely is Safari (5.1.4). In Opera 11.62 the gradient is black, in IE 9 and Firefox 12 it's white. In Chrome 19, it works UNLESS you specify the width/height of the SVG in % units. I'd say it's more of an oddity than a real feature. It's a cool find though.
  • Right... still I'm anxious to see the looks on my coworkers' faces when I show them a cute little monster like this so thanks again for showing it's possible. I just went to the standard specification and stated it was virtually impossible, which turned out to be a mistake (sort of)
  • The "browser incompatibility" here is mostly just a lack of proper URL escaping, everything inside url() should be url-escaped. See jsfiddle.net/6WAtQ for an example that works just fine in Opera, Firefox and Safari.
  • Is there any compatibility difference between base64 encoded svg to non-base64? Base64 bloats my css file, I'm thinking in just use inline svgs..
  • Note, the standard way to specify the character set is with ";charset=UTF-8" instead of ";utf8". tools.ietf.org/html/rfc2397
  • Thanks, man. The solution with Base64 worked excellent, while I ran into trouble with the accepted answer.
  • You saved my life. I had a SVG border image that was working in chrome but not on FF. Now it works! :D
  • Helped me as well (after loosing time trying out the accepted answer) - this should definitely be the accepted answer.
  • Will this work as an in-line data-src?
  • If this is still not working for you - make sure you have xmlns attribute set to svg element before you base64-encode like <svg xmlns="http://www.w3.org/2000/svg">...</svg> browsers sometimes chunk it without it when svg is directly in HTML - this is NOT the case :)