Skip to content

Inline SVG with PNG Fallback

David Ensinger

Notice anything different about my balloon logo? Probably not, as the change is subtle, but the image is now an inline SVG instead of an SVG background image. I did this to allow the colors of the balloon to darken on hover.

Please Note: As of this commit, I’ve stopped using this fallback technique for browsers and devices that don’t support inline SVG. This affects IE8, Opera Mini, and Android 2.3, all of which provide a negligible amount of traffic to my site. In spite of this change, I still feel that this is a good solution for providing a PNG fallback.

Using an inline SVG is the only way to do this, as the browser regards the other implementations of SVG as externally linked files. That prevents the browser from respecting any inline CSS pseudo classes within the SVG.

As an added benefit, an HTTP request is saved, although this boon to page load optimization is at the expense of the tidiness of the markup. It’s not such a drawback, especially if the HTML will be minified before being deployed.

As for browser support, inline SVGs are supported by all modern browsers, so long as the proper HTML5 DOCTYPE (<!DOCTYPE html>) is declared. Not surprisingly, IE8 doesn’t support inline SVGs, so a fallback is needed for the small percentage of visitors who use that browser.

The obvious choice for an image fallback is a PNG since they support alpha transparency and are easily optimized for file size with ImageAlpha and ImageOptim.

How Best to Fallback?

I initially considered replacing the inline SVG markup with an img tag via either JavaScript or jQuery, but decided against it. The user may have JavaScript disabled and if I elect to use jQuery I’ll need to make an additional HTTP request to load the library.

Thankfully, I stumbled upon a better solution that makes use of foreignObject and switch, which are both elements specific to SVG.

The foreignObject element allows for inclusion of a foreign XML namespace which has its graphical content drawn by a different user agent.

Mozilla Developer Network

With foreignObject I can insert fallback HTML into the SVG, which will look like this:

<svg>
  SVG
  <foreignObject>
    Fallback HTML
  </foreignObject>
</svg>

The final step is to put the SVG code into a group (g) and then wrap the group and foreignObject in a switch (switch) element. The switch will then evaluate the children elements in order. The first element that has the proper attributes will be rendered, which will be the group with the SVG.

<svg>
  <switch>
    <g>
      SVG
    </g>
    <foreignObject>
      Fallback
    </foreignObject>
  </switch>
</svg>

Browsers that support SVG will render the inline SVG, while older browsers will instead display the foreignObject, which contains the fallback PNG. Easy and efficient, right?

Unfortunately, both the SVG and the image fallback will be loaded by the browser. This isn’t such a big deal, so long as the image is optimized and then converted to a base64 string, thus saving another HTTP request. I recommend my favorite converter for the task!