HTML markup

Transitioning the colour of an SVG image

So when trying to make the BTB website load as quickly as possible (which requires an unhealthy obsession with tweaking small things to get a better score on Google page speed insights) I removed Fontawesome, which was previously baked into our CSS file. I like Fontawesome, it makes adding icons easy, but has problems, and in this case the problem was unnecessary addition of loads of styles we didn’t need, and valuable kilobytes of data I wanted to shave off.

So this meant replacing the social icons with SVG equivalents.

Social icons

Which was a good idea until I realised I needed to change the colour of the icon when the button was hovered. Worse, I needed to transition from one colour to another. Something that’s not possible with an SVG if you’re adding it as an <img> element, like I was.

An option was to use filter: brightness() to make a dark icon light, or light icon dark. But that doesn’t work in IE11, and only works when making the icon light/dark, in the side-menu it actually needed to transition between white and red. So that wouldn’t work.

Another option was to embed the SVG code into the HTMl, so instead of embedding the SVG as an image (e.g. <img src=”icon.svg”>), you paste the entire code into the HTML, which allows you to target the <path> with CSS, and give it a .fill value of the colour we want.

SVG code on the path

Thing is, this is a bit messy, and I don’t like it! Also it adds to the amount of HTML which is downloaded for every page, whereas the <img> file would be cached and only loaded once.

So I’ve gone for a solution found on Stack overflow (see here) where a JQuery snippet takes the SVG image element and puts it inline (only if it has a class=”inline-svg”). This allows me to target the <path> in css and apply the appropriate fill colour.

Here’s the JQuery code needed. I’ve put it in a file called “make.svgs-inline.js” and minified it with the rest of the Javascript:

/*
 * Replace all SVG images with inline SVG if it has the class "inline-svg"
 */
jQuery('img.inline-svg').each(function(){
    var $img = jQuery(this);
    var imgID = $img.attr('id');
    var imgClass = $img.attr('class');
    var imgURL = $img.attr('src');

    jQuery.get(imgURL, function(data) {
        // Get the SVG tag, ignore the rest
        var $svg = jQuery(data).find('svg');

        // Add replaced image's ID to the new SVG
        if(typeof imgID !== 'undefined') {
            $svg = $svg.attr('id', imgID);
        }
        // Add replaced image's classes to the new SVG
        if(typeof imgClass !== 'undefined') {
            $svg = $svg.attr('class', imgClass+' replaced-svg');
        }

        // Remove any invalid XML tags as per http://validator.w3.org
        $svg = $svg.removeAttr('xmlns:a');

        // Check if the viewport is set, if the viewport is not set the SVG wont't scale.
        if(!$svg.attr('viewBox') && $svg.attr('height') && $svg.attr('width')) {
            $svg.attr('viewBox', '0 0 ' + $svg.attr('height') + ' ' + $svg.attr('width'))
        }

        // Replace image with new SVG
        $img.replaceWith($svg);

    }, 'xml');

});