In the process of updating an old site to be mobile friendly, I decided to replace the site’s logo with an SVG, so it will look better on high DPI screens. Old browsers, such as IE < 9 and Android 2.3 don’t support SVG. So we need some way of serving a bitmap image (PNG) to them while serving SVG to browsers that support it.
An excellent article on various SVG fallback techniques, and the pluses and minuses of each technique is SVG Fallbacks on CSS-Tricks. In the comments to that article it is suggested using an
<object> tag for the SVG with a
<img> for the PNG nested inside as the fallback.
No response for or against was given to this suggestion, so I thought I’d try it out. The code was like this:
<object type="image/svg+xml" data="/images/logo.svg" > <img src="/images/logo.png" alt="Logo" /> </object>
I then tested this page in Chrome and IE6, using a clean cache and Fiddler to view the HTTP requests made.
Chrome would request the fallback PNG first, and then the SVG.
IE would request the SVG then make a request to http://activex.microsoft.com/objects/ocget.dll
and http://codecs.microsoft.com/isapi/ocget.dll, both of which 404. Then finally it would request the PNG. There was a visible red X for the image for a second or so until the PNG was loaded.
So, not a good result. Chrome makes 2 HTTP requests and downloads a PNG it doesn’t need. IE downloads an SVG it doesn’t need and makes 4 HTTP requests!
I then tried the solution listed in the CSS-Tricks article that seemed neatest to me. This was:
<img src="/images/logo.svg" alt="Logo" onerror="this.onerror=null;this.src='/images/logo.png';" />
This technique uses inline js for the
onerror event to load the PNG if the SVG can’t be loaded / displayed. It is important that
this.onerror=null comes before you try to change the image’s src. Otherwise you’ll get a stack overflow if the src you are trying to change to can’t be loaded / displayed either. (I found this out by accidentally setting the fallback image to an SVG too).
The result for this technique was that Chrome requests just the SVG, while IE requests the SVG and then the PNG.
The downside of this technique is that browsers that don’t support SVG still download the SVG image (and I suspect they wait until they receive it to work out they can’t display it, and then request the PNG). However, in my mind this is a better trade-off than the other main fallback method, where modern IEs that can display SVG also download the PNG. (See the CSS-Tricks article for details).