Fallback for SVG injection with no Javascript/SVG support

Viewed 1766

We are looking into using Iconfu SVGInject to inject SVG files into our HTML files. One of our projects for some reason still requires support for IE8 (don't ask), so I was forced to test this with really old browsers.

There is a fallback example for no SVG support in the SVGInject docs, which looks like this (image dimensions added by myself):

<html>
<head>
  <script src="svg-inject.min.js"></script>
</head>
<body>
  <img src="image.svg" width="128" height="128" onload="SVGInject(this)" onerror="SVGInject.err(this, 'image.png')" />
</body>
</html>

While the fallback works on standard configuration of IE8, I found that there is no fallback for cases if neither SVG nor Javascript is supported by the browser (for example IE8 with Javascript disabled).

Here is what is displayed in the different scenarios:

Modern Browsers (Chrome, Firefox, Webkit)

The SVG is injected as an inline SVG, fully styleable

Modern Browsers, Javascript disabled

The SVG is displayed as an <img>, not styleable

Internet Explorer 8

Fallback PNG is displayed

Internet Explorer 8, Javascript disabled

Broken image is displayed

The reason why no image is displayed in the last scenario is that the onerror is never fired, therefore the fallback source attribute cannot be set.

I was wondering if there is a way (or a hack) to make the fallback image display even in cases when neither SVG nor Javascript support is available.

Note: This is more a theoretical question. Although the project requires IE8 support, I think this is some legacy requirement, as the requirements were written in 2010.

1 Answers

There is actually a way to do this, but it is not perfect, because is has a performance impact on Internet Explorer 9, 10 and 11.

Here is the implementation with full fallback for no Javascript and no SVG support:

<html>
<head>
  <script src="svg-inject.min.js"></script>
  <script>
    // Wrapper for SVGInject that does a little preprocessing
    SVGInject2 = function(img, options) {
      if (typeof SVGRect != 'undefined') { // check if SVG is supported
        // replace src with srcset if srcset is provided
        var srcset = img.srcset;
        if (srcset) {          
          img.src = srcset;
        }
        SVGInject(img, options);
      }
    }
  </script>
</head>
<body>
  <img src="image.png" srcset="image.svg" width="128" height="128" onload="SVGInject2(this)" />
</body>
</html>


How does it work?

As you may know there is a srcset attribute for the HTML <img> element, that has priority over the src attribute if provided. srcset is supported by evergreen browsers (Chrome, Firefox, etc), but not by Internet Explorer (all versions).

If Javascript is disabled, the PNG specified in the src attribute will be displayed on Internet Explorer. On modern browsers, the srcset attribute with the URL to the SVG will be used.

If Javascript is enabled, the function SVGInject2() is called after the image has loaded. This checks if SVG is supported by the browser. If no SVG support is detected, it does nothing. This should only happen on IE8 and older, which will display the PNG, just as if Javascript was disabled. If SVG support is detected, the value of the src attribute will be replaced with the value from the srcset attribute and the SVGInject() function is called. This loads the SVG (using the URL from the src attribute) via XHR and replaces the <img> element with the loaded SVG. In most cases the browser has the SVG already in the cache (from the initial load), so the SVG is only transferred once over the network.

However, there is a negative performance impact on Internet Explorer 9, 10 and 11. On these browsers the PNG will be loaded in any case, because srcset is not supported. If the SVG is injected the PNG is not used, which means the PNG transfer is unecessary. On other browsers there should be no performance impact when using this fallback method.

Disclaimer: I am one of the authors of SVGInject.

Related