CodePen probably won't work great in this browser. We generally only support the major desktop browsers like Chrome, Firefox, Safari, and Edge. Use this one at your own risk! If you're looking to test things, try looking at Pens/Projects in Debug View.

Coloring SVGs in CSS Background Images

I love using SVG in CSS background images but it sucks that you can't alter the fill color easily within your CSS. Here are a few ways around that.

SVG in CSS backgrounds

Using SVG in CSS backgrounds allows you to use CSS's powerful background sizing and position properties. This makes sizing SVGs much simpler because the image easily scales to the size of your element. Plus you don't have SVG cluttering up your markup.

There are also some nice performance benefits over inline SVG. An SVG in a background image can be cached. Using image sprites and embedding SVG as a data URI can also improve performance.

CSS masks

This is my favorite method, but your browser support must be very progressive. With the mask property you create a mask that is applied to an element. Everywhere the mask is opaque, or solid, the underlying image shows through. Where it’s transparent, the underlying image is masked out, or hidden. The syntax for a CSS mask-image is similar to background-image.

Here I'm setting an SVG as the mask. The fill of the icon in the SVG doesn't matter because it masks the background layer which is the color red. Therefore, the result is a red icon. For webkit, I'm using the prefix.

There are a bunch of properties related to mask, such as mask-position, mask-repeat, and mask-size, which align with CSS background properties. You can use the mask shorthand like the background shorthand:

In this example, the icon has a pure red fill set in the SVG. The hue-rotate filter rotates the hue 220 degrees around the rgb color wheel. This makes the icon blue. The algorithm for hue-rotation isn't extremely accurate, so although the output should be pure blue it’s a little off. One way to fix this and boost up the color to full saturation is to add a saturation filter. In the example, I added an arbitrarily large value of five to the chain, which increases the saturation by 500%.

By chaining filters together, you can make many colored icons from one colored icon input. With different combinations of hue-rotate, invert, brightness, and saturation filters, I've created the ROYGBIV rainbow spectrum and some other basic colors like cyan and magenta.

Creating a grayscale set of filters is pretty easy. You add a grayscale filter and adjust a brightness filter to the amount of gray you need.

This technique isn't super intuitive. It will probably require some trial and error to find the colors you need, especially since the algorithms aren't perfect. In the future, it would be fantastic if CSS filters could also work in HSL space, as they would be much more intuitive.

CSS filters are supported well in most browsers. IE has them listed as "In Development", which means they are in active development and should be added to IE soon.

Data URI

As Chris Coyier demonstrated in his article, Probably Don't Base-64 SVG, properly formatted, you can pop SVG XML right into your CSS. Using this technique, and a bit of Sass magic, I've created some functions that allow you to dynamically change the color.

With this setup, add the path coordinates of your SVG to a Sass map with a key and invoke the function with your parameters. You call the function with the icon's name, which corresponds to the key in the map. You can pass in arguments for color, stroke-color, and stroke-width. You can also do other fun stuff like pass in any SVG valid CSS, as I did with the stroke-dasharray in the last example.

With proper URL encoding, this will work in IE. Obviously its quite intricate to get right.

SVG Background Sprite

Creating sprites for SVG uses the same concepts as normal image sprites. The sprite contains all of the versions of an image. By manipulating the background-size and background-position in your CSS, you choose which version to display. Here's how to set up an SVG sprite:

Use the xmnls namespace attribute or the SVG won't work in your background. Also include the xmlns:xlink attribute if using links, which I am in the use tags. The width and height need to be large enough to contain all of the images. In the example I'm using twenty-four 24x24 icons stacked vertically, so my SVG dimensions are 24x576 (24 times 24 = 576).

I'm using the symbol and use tags to keep the file size low. Define the icon shape as a symbol and place it in a defs block. Give it an id. Employ the use tag to stamp out versions of this symbol. In the use tag, the y coordinate is adjusted so the icons stack on top of each other at 24 unit increments. The fill attribute colors the icon. Here's a demo with a bunch of different colored icons defined using this technique.

In the future, it would be fantastic if CSS filters could also work in HSL space, as they would be much more intuitive.

I'm not sure what more you need for filters to work in HSL space. CSS filters have hue-rotate and saturate, and brightness I'm pretty sure only applies only to the lightness channel in an HSL model. Did you maybe mean you wished filters could work in RGB, like the SVG ``?

Interesting. I'll have to look up the exact definitions and see what's going on there. Could be a linearRGB vs sRGB thing. I think CSS filters operate in sRGB by default, versus SVG filters used linearRGB (and could be modified by setting the color-interpolation-filters property on the `` element.

(The color stuff would be the same in other browsers, but Firefox is the only one that lets me reference an SVG filter within a data URI created in SASS.)

So, the conclusion:

As I suspected, the main problem is linearRGB versus sRGB. The CSS filter functions always operate in an sRGB-adjusted color space, as opposed to SVG filters which operate in linear color space by default and can be switched to sRGB if required.

However, an additional complication is that the hue-rotate filters operate in an HSLuminance color space, instead of the HSLightness color space used by the hsl() color function.

Feel free to send a thoughtfully-worded rant to the public-fx email list explaining why this is a problem. I don't think they'd change the default behavior at this point, but maybe it could be possible to add an extra parameter(s) to the function, like:

@GreLI that is a really good idea, and would work great in the situation you've mentioned. I've seen some weird rendering bugs in Chome (haven't tested others) when using inline-block with this technique, but I might dig further to find a bullet-proof solution.

Thanks for this great article. I've checked your codepen (http://codepen.io/noahblon/pen/qEByrR) and that seems to be the best of both worlds: the customisation allowed by inline SVGs (in this case encoded directly in SASS rather than in the HTML) and the optimisation of loading (in this case minified in a CSS file rather than in a sprite).

Did you manage to find a Grunt plugin that will output SASS code like in that codepen?

CodePen

We're all for progressive enhancement, but CodePen is a bit unique in that it's all about writing and showing front end code, including JavaScript. It's required to use most of the features of CodePen.