As most of us know, SVGs load faster than images, are dynamically flexible for clear scaling, and generally are the preferred way of rendering anything that could be generated by vector on the web. Recently, I had a task to set a background image that was an SVG and I wanted to reuse an item I was using elsewhere on the site, but in a different color. However, you can't use background-color
, fill
, or stroke
on a background image SVG, so what is the best way to dynamically change the fill or stroke of the image if you need to use it in different circumstances? A bit of googling took me down a rabbit hole that lead me to the solution: a mixin, a function, and a bit of encoding!
The first thing to note about this is that there are limitations to this solution - you cannot use the sass alpha parameters to fill your SVG code, which means that if you are using a variable with an alpha parameter it won't work. Solid colors only!
Let's start at the bottom. Because we will be encoding our SVG directly into the background-image
call, we need a function to strip the hash tag off the beginning of hex code variables. I snagged this handy-dandy function off a google search for this very query and it's zippy enough to replicate:
@function encodecolor($string) {
@if type-of($string) == 'color' {
$hex: str-slice(ie-hex-str($string), 4);
$string: unquote("#{$hex}");
}
$string: '%23' + $string;
@return $string;
}
Now that we have our encodecolor()
function, we can use that in the mixin we're going to create to add our SVG background image. But first we need the image - I'm going to use the play button that I have in my project as the example for this, and this is the raw SVG code for it:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24" xml:space="preserve">
<path fill="#ccc" d="M2.4 20.6V3c0-1.5 1.7-2.5 3-1.7l14.9 8.9c1.3.8 1.3 2.7 0 3.4L5.4 22.3c-1.4.8-3-.2-3-1.7z"/>
</svg>
Now we can take that and put it inside a background-image
call in a mixin, where we set the fill on the path to be our encoded color. You can have more than one of these variables if you want to dynamically change the color of multiple paths - no limitations (except alpha, of course)!
@mixin play-button($color) {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24" xml:space="preserve"> <path fill="#{encodecolor($color)}" d="M2.4 20.6V3c0-1.5 1.7-2.5 3-1.7l14.9 8.9c1.3.8 1.3 2.7 0 3.4L5.4 22.3c-1.4.8-3-.2-3-1.7z"/> </svg>');
}
As you can see, we have our path's fill set to fill="#{encodecolor($color)}"
, which takes our variable, runs it through the encoder, and passes it into the background-image for the SVG's URL.
To implement, you can call it directly with a hex code or use a sass variable, like so:
html {
@include play-button(#000);
}
header {
@include play-button($branding-red);
}
Voila! A mixin with an encoded hashtag to render dynamically filled (or stroked, you can use it on stroke, too!) background SVG images. Enjoy!