By Luke Haas

A Graceful Fallback for SVGs in Old IE

By Luke Haas

There are plenty of good reasons to use SVGs instead of rasterized images. The benefits include better image quality, image flexibility, and smaller file size. But one obstacle you might still face is browser support. SVGs are supported by all modern browsers except IE8 and below.

In the following sections I’ll outline how you can handle this in a graceful way by falling back to PNGs for older browsers. This will address both inline SVGs and background images.

Produce your Fallback Images

The first step is to produce a PNG version for each of your SVGs. You could do this with your preferred image editing software, but that could be a slow process if you have a lot of SVGs. Alternatively, you can use Grunt and a Grunt module called svg2png. This is the solution I will be describing in the following steps.

If you’re not familiar with Grunt, I recommend you read through this getting started guide. Otherwise, you can make a start by preparing a Grunt project and then running the following command:

npm install grunt-svg2png --save-dev`

Configure Your Grunt File

Configure your Grunt file with the following additions:


    svg2png: {
        all: {
            files: [
                { cwd: 'img/', src: ['**/*.svg'], dest: 'img/png/' }

Make sure to point the cwd property to the directory containing your SVGs. Once that’s done, run grunt svg2png and you should now have a folder full of PNG versions of your SVG files.

Handling Inline SVGs

If you are using SVGs as inline images, the most robust fallback is to add an inline onerror event to the image tag like this:

<img src="/img/image.svg" onerror="this.src='/img/image.png';this.onerror=null;">

This will swap out the SVG for the PNG image if the SVG fails to load. I’ve also added an extra bit at the end: this.onerror=null;. This is to stop the event from firing again, which could happen if there was an issue with the path of the PNG. This would then cause an infinite loop of event calls, which is obviously best avoided.

You may be wondering why I’m suggesting an inline event here rather than a less obtrusive approach of attaching an event in a separate JavaScript file. This is because a jQuery approach of $("img").on("error", handler); won’t work in IE8 and lower because of timing issues, and the other alternative of looping through all images and attaching an error event to them would be a drain on resources for all browsers unless you just targeted older ones.

Handling SVGs as Backgrounds

If you are using SVGs as background images in your CSS then there’s a simple way to fall back to PNGs. The support for SVG is roughly in line with support for multiple background images. This means you can use a pure CSS solution, and so the following declarations are all you need:

background: url('/img/image.png') no-repeat;
background: none,
            url('/img/image.svg') no-repeat;

Here we are setting a PNG as the background but then overriding it with an SVG for browsers that are able to support multiple backgrounds on the second line.

IE8 and lower will view the second declaration as an error, so it will ignore the entire line, using only the first background.


That’s all there is to it. Now I hope going forward you’ll use SVGs even in projects that still require support for older versions of IE. This means you’ll be safe in the knowledge that they can gracefully degrade to PNGs if needed.

If you have some other automated solution for dealing with SVGs in IE8 and below, I’d love to hear about it.

  • TroyBatty

    This looks pretty easy to implement – thanks.

  • Paweł Grzybek

    very cool idea with overwriting background image. I did very similar job via modernizr, but this one does the same job and its way easier. Thanks for sharing!

  • MattDiMu

    Basically a nice tutorial. I think I should really try the automation with grunt!
    About the Fallback-Trick with multiple backgrounds. I’ve seen it multiple times in the web and I’m still not convinced. I think, that the modernizr-Fallback like mentioned by Pawel Grzybek

    .class { /* include svg here */ }
    .no-svg .class { /* include png here */}

    is the better way to go. Why?

    – The browser support for multiple backgrounds is better than for svg (i.e. Android 2.3) So these browser wouldn’t show any icon at all !
    – What about other browsers we don’t know? The Modernizr-Fallback is browser-agnostic and will work in every browser no matter what combination of features it supports.
    – You don’t have to deal with multiple backgrounds and their consequence on other background-properties. What if you have an extra background-repeat property, which is added by another class? Then you would have to write the value 3 times instead of just once:

    background-repeat: no-repeat; /* for the png */
    background-repeat: no-repeat, no-repeat; /* for the svg */

    The same goes for any other background-property.

    – Finally (that’s my personal opionion), the modernizr solution seems to be more “clean”. I can use CSS & Icons the standard way and just add a Fallback for older browsers (probably with a sass/less/stylus-mixin). I’ve got this clean separation of my code and my fallback.

  • Mig

    I’m with MattDiMu on this one. But I would add “.no-js .class” to the declaration, in case Modernizr doesn’t load. I really love the grunt task, though! Thanks for that!

  • l2aelba

    Or just use Modernizr ?

    Example :

    .myclass {
    background: url( hello.png ) no-repeat;
    .svg .myclass {
    background-image: url( hello.svg );

  • FWIW, you can also implement SVGs and PNGs in the same markup:

    The Grunt task looks quite interesting, but in my workflow I don’t work with THAT many SVGs that warrant the use of Grunt, at least yet :p

  • lukehaas

    Thanks everyone who commented, some great points raised.
    Using Modernizr is definitely a perfectly valid alternative way of handling the background SVGs. My point simply describes the vanilla way of approaching this problem.

Get the latest in Front-end, once a week, for free.