Ashley Sheridan​.co.uk

Colouring SVG Background Images With SASS

Posted on

Tags:

SVG images have two main benefits over traditional raster or bitmap images: they can scale to any size without a loss of quality, and they allow for more control over their appearance, such as changing the colour of parts of the image in response to a particular user action.

The Two Types of SVG Background Image

There are two ways to set an SVG background image via CSS, and only one allows any control over the colour of the component parts of the image:

  1. Include via a standard background-image: url() line set to the path of the image. This will result in an extra HTTP request, which will impact performance badly if there are a lot of images included in this way.
  2. Include via background-image: url(data:image/svg+xml;). While this does increase the size of the CSS file, this is often preferable to many HTTP requests. It does also let us have a degree of control over the SVG content.

Changing Colours with a SASS

What led up to my need to do this was a recent project that involved SVG icons coloured according to a set of specific user-selected colours. The same icon needed to be used across multiple websites, so embedding the SVG code into the HTML was not an option if we were to avoid technical debt from duplicated code. The multiple websites only had a single SASS/CSS project in common, so this was the perfect place to put an icon.

In order for this to work, I used a bit of string manipulation to insert colour variables at the right points in the SVG code:

.svg-icon { background: url('data:image/svg+xml;%3Csvg ...%3E'); }

First, the whole SVG is inline in the CSS, but not as a base64 string. This should reduce the file size (base64 is longer than the raw source its encoding, even with the escaped characters here), but also will have more duplication that lends itself well to gzip compression. You can typically run the SVG code through any URL encoder, although Chris Coyier recommends the SVG URL encoder from Yoksel.

Once that's done, locate the colours you wish to change into their SASS variable counterparts. The hash is URL encoded and will now be %23, e.g. %23ff8800.

Now, SASS will complain if you just shove the colour variables in there, as they're two different types of things and it won't know how to handle the situation without a little help. What you need to do is replace each 6-digit hex code with the following (including the quotes!):

' + str-slice("#{$variable-name}", 2) + '

This forces the colour in our variable to be cast to a string (because of the slicing). It's worth noting that this string slice method uses indexes which start at 1, rather than 0, which might be confusing at first. Your end result should look a bit like:

background: url('data: ... %3Cpath fill="%23' + str-slice("#{$background}", 2) + '" ... /%3E'); This will work for other things as well beyond colours. Want that SVG shape to have a specific width border to match the surrounding HTML elements on the page? Not a problem. Want the line style to match the same dash style on the borders of those box out elements on the page? Why not!

Conclusion

While background images don't afford us the full scope for change that an inline SVG does, there are things that can be controlled. One thing to remember though is that SASS is a pre-processor, it performs its work before the browser is even in the picture. That means we cannot use elements that we need to rely on a browser to load, like fonts or images. An inline SVG will almost always be the preferred choice, but in those few cases where it's not possible, then you should know that it's not _always_ completely fixed in state.