The following is a guest post by Amelia Bellamy-Royds and me. Amelia and I recently presented at the same conference together. We both covered SVG, yet neither of us SVG fallbacks comprehensively. It’s such a huge topic, after all. While I’ve covered SVG fallbacks before, it’s been a few years and we figured we could do that subject better justice now. Here we go!

Some tech-oriented web sites (like this one) can afford to say that they only support modern web browsers. But for most sites, you can’t ignore 1 in 20 potential customers. If you want to give the 95% of users on modern browsers all the benefits of SVG, but still provide a functional experience for the others, you need a fallback plan.

Maybe they are stuck on an office computer that hasn’t been updated since the IT guy quit six years ago, maybe they’re using a second-hand refurbished phone they can’t afford to upgrade, or maybe they just don’t understand or don’t care about updating to a new browser. Whatever the reason, approximately 5% of users browsing the web are doing so with web browsers that can’t display SVG—more in the USA (according to caniuse data ).

Here at CSS-Tricks, there’s a lot of information telling you how wonderful SVG is . And as much as we want to convince you that SVG is for Everybody , SVG isn’t as widely used as we would like. In fact, some people still (literally) don’t get SVG.

The rest of this post covers the ways to create text and image fallbacks for your SVG. Your options will depend almost entirely on how you’re including that SVG in the web page in the first place: as an embedded object, as inline SVG code, as an image in the HTML, or as an image in the CSS.

On the interactive front, your options are limited. You could convert the SVG to Flash and then rewrite all your interaction code in ActionScript. Or you could use Raphaël to both draw and manipulate the graphic. It provides a single JavaScript interface to both SVG and the VML vector graphics supported in Internet Explorer 6-8. Which means that Raphaël doesn’t help with old mobile browsers, but it does cut down the number of unsupported users significantly.

Before getting into the technical options for implementing fallbacks, it helps to stop and think of what kind of fallback you need:

Besides excluding a few older browsers that can support SVG images but not inline SVG, the main limitation here is that it will be a lot more work to get the images to display the correct size on a fluid site. You’ll need to use the same tricks used to get an SVG to scale to a consistent aspect ratio , instead of just setting width: 100%; and letting the height adjust automatically.

Be sure to add sizing attributes to the image so that it fills up the entire SVG, and then size both svg (for modern browsers) and image (for old ones) in your CSS.

You can polyfill the picture element though, with Picturefill . Sara Soueidan has an article that covers this .

Unfortunately that’s not much use when support for SVG is much better than support for <picture> .

SVGMagic is another JavaScript library that swaps out sources with PNG versions, including SVG used in <img> , background-image, or even inline. It’s biggest advantage is that it creates the PNG version for you automatically, by request to a third-party server. So just beware the dependencies (jQuery and third-parties) and test for speed and reliability.

SVGInjector is a JavaScript library that can help with <img> fallbacks in specific scenarios. It’s main purpose is to replace <img> with inline SVG.

If you were doing feature detects with Modernizr and also utilizing jQuery on a project, it could be as simple as this:

If for some reason you couldn’t get this into external JavaScript and had to do it inline…

Advantages: It’s easy. It works. You can even write your own source-swapping JavaScript pretty easily. Disadvantages: It’s likely the non-supporting browsers will download two images, which is a performance penalty. It will download the SVG version (at least enough to know it can’t use it) and then the PNG version.

The test above is what the SVGeezy library uses to do SVG-as-img fallbacks. If the browser fails this test, it will swap out the SVG with a PNG as needed. As in <img src="image.svg"> turns to <img src="image.png"> . You create the PNG versions yourself and have them available in the same directory.

Even though this test is supposed to test for the <image> element within SVG, thanks to some testing we’ve proven it works for SVG used as the source for <img> elements as well. It’s this easy :

Another progressive-enhancement benefit of <object> : some users on Internet Explorer 8 (and under) will be able to see the SVG! Objects trigger plug-ins, and the no-longer-updated Adobe SVG Viewer plug-in is still available for download for old IE.

The child content of the <object> element is displayed if the object itself cannot be. That content can be any html content: images, formatted text, even another object (for example, one containing a Flash version of your animated SVG).

As inline SVG has become better supported, SVG as <object> has fallen out of favor. That’s unfortunate from a progressive enhancement/graceful degradation perspective, because this is the easiest way to provide fallback content.

You might add a slight performance hit on modern browsers from having to calculate the transparent gradient, but it’s probably negligible.

This combines two features that, together, target the perfect combo. If a browser supports both multiple backgrounds and linear gradients, it supports SVG too. So here we declare the SVG with a completely transparent linear-gradient. If that fails in an older browser, the fallback declared above will kick in.

The trick here is to find syntax that is supported by (nearly all) browsers that support SVG, but not by the older browsers. Here’s the magic:

For most CSS properties, you can trust in CSS error handling to get the browser to ignore a new syntax and apply a value declared earlier in the cascade. However, the syntax of a CSS rule using an SVG image file is perfectly correct for the old browsers. So they apply the rule, download the file, but then don’t know what to do with it.

Inline SVG is popular for many reasons. All the code to draw what needs to be drawn is either right there in the markup (reducing requests), or referenced from a file that can be cached. You have lots of control over SVG that is inline. It’s in the DOM, so it can be controlled with CSS and JavaScript from the same document.

There are some great tests from Modernizr that we can look at. Your best bet for inline SVG, extracted out into a function, is this: function supportsSvg() { var div = document.createElement('div'); div.innerHTML = '<svg/>'; return (div.firstChild && div.firstChild.namespaceURI) == 'http://www.w3.org/2000/svg'; }; This tests if the HTML parser (which is what is used to parse content sent to innerHTML) can correctly generate an SVG element, basically by creating an element, injecting SVG, and testing the namespace. As with <object> , a browser that doesn’t recognize <svg> will just ignore your SVG markup and treat its contents as HTML. But its not that simple. With <object> , browsers that do support the object will know to ignore the child content. With inline SVG, there’s no such built-in fallback. However, there are a few workarounds you can use.

You can include plain text inside your inline SVG code, and it will be ignored by any browser that supports SVG, because SVG text must be contained in a <text> element. You can even include hyperlinks within that text. <svg viewBox="-20 -20 40 40"> <!--Text Fallback--> I'm sorry, your browser does not support <circle fill="limegreen" r="19" /> <path stroke="forestgreen" fill="none" stroke-width="6" d="M-12,3 L-3,10 11,-12" /> <text dy="0.35em" text-anchor="middle" font-weight="bold" font-size="18px" font-family="sans-serif" fill="indigo">SVG</text> <!--Fallback with links--> Please upgrade to a <a href="http://browsehappy.com/?locale=en">modern browser</a>. </svg> See the Pen SVG Fallbacks: Inline SVG – Plain text by Amelia Bellamy-Royds (@AmeliaBR) on CodePen. Plain text fallback, as it appears in Android 2.3 Things to note: The SVG text (the word “SVG” in this demo) becomes part of the fallback text. We’ll talk about how to avoid this in a moment.

The SVG <title> text does not become part of the fallback text. That’s because the no-SVG browsers interpret this as an invalid second HTML title element, and ignore it. You cannot include any other HTML content within inline SVG: when the HTML parser in a modern browser reaches an HTML tag, it assumes that you forgot to close your <svg> tag, and closes it for you. Which means that (a) your SVG is corrupted and (b) your fallback text is visible in modern browsers. The only reason you can use links ( <a> tags) is because they are valid tags in SVG, but don’t draw anything themselves. Another approach here would be to start with HTML text, and swap it out with inline SVG should you detect with JavaScript it is supported. Imagine a “like” button in HTML: <button aria-label="Like"> <span class="inline-svg" data-xlink="#icon-heart">♥</span> Like </button> The span with the ♥ is the fallback there. The data attribute is what we’ll use for a fallback, in this case, a <svg> / <use> element. if (supportsSvg()) { // see test above var inlineSvgs = document.querySelectorAll('span.inline-svg'); for(i = 0; i < inlineSvgs.length; i++) { var span = inlineSvgs[i]; var svgns = "http://www.w3.org/2000/svg"; var xlinkns = "http://www.w3.org/1999/xlink"; var svg = document.createElementNS(svgns, "svg"); var use = document.createElementNS(svgns, "use"); // Prepare the <use> element use.setAttributeNS(xlinkns, 'xlink:href', span.getAttribute('data-xlink') ); // Append it svg.appendChild(use); // Prepare the SVG svg.setAttribute('class', "inline-svg"); // Set a title if necessary. if (span.getAttribute('title')) { svg.setAttribute('title', span.getAttribute('title')); } // Inject the SVG span.parentNode.insertBefore(svg, span); // Remove fallback span.remove(); } } See the Pen Critical Inline SVG Fallbacks v2 by Dave Rupert (@davatron5000) on CodePen.

You can use HTML text-formatting markup without ruining the SVG by including it within SVG <desc> (description) tags, which allow content from other namespaces. <svg viewBox="-20 -20 40 40"> <desc> <p class="warning"> Fallback text. </p> </desc> <!-- ... SVG content ... --> </svg> See the Pen SVG Fallbacks: Inline SVG – Formatted Text by Amelia Bellamy-Royds (@AmeliaBR) on CodePen. Formatted text fallback, as it appears in Internet Explorer 8 Things to note: The main purpose of the <desc> tag is to provide alternative text description. Make sure the content of the tag makes sense to a screen reader.

tag is to provide alternative text description. Make sure the content of the tag makes sense to a screen reader. In order for <desc> to be recognized by accessibility technologies on all browsers, it should be at the top of the SVG, right after the <title> .

to be recognized by accessibility technologies on all browsers, it should be at the top of the SVG, right after the . You should also be able to use an SVG <metadata> tag to include all sorts of arbitrary markup without affecting the SVG or its alternative text. However, this doesn’t work in browsers tested (they insert implicit </svg> end tags).

tag to include all sorts of arbitrary markup without affecting the SVG or its alternative text. However, this doesn’t work in browsers tested (they insert implicit end tags). The SVG text content still gets included in the fallback text. You could even include an <img> tag with a fallback image within the <desc> and it would display correctly in the old browsers without breaking your SVG in the new browsers. Don’t do this! Although modern browsers do not display the fallback image, they do download it, and we’re always trying to avoid double-downloads.

A possibility for an inline <svg> fallback is to set a background-image that is only used if the browser doesn’t support inline <svg> . So, using the test above, you give yourself a class to work with: if (!supportsSvg()) { document.documentElemement.classList.add("no-svg"); // or even .className += " no-svg"; for deeper support } Then say you’re using some inline SVG like this: <button> <svg class="icon icon-key"> <use xlink:href="#icon-key"></use> </svg> Sign In </button> You could use that new class to apply a background-image if needed: html.no-svg .icon-key { background: url(fallback-key.png) no-repeat; } Demo: See the Pen Inline SVG Fallback by Chris Coyier (@chriscoyier) on CodePen. You’ll have to create the PNG and size it yourself. There is a walkthrough article here on CSS-Tricks about using Grunticon to automate all this. For the deepest possible support, you’d wrap the <svg> in a <div> and apply the background to that, so even if the browser totally rejects the SVG element, the fallback will still work on the known DIV element.