<svg style="display:none;">
<defs>
<symbol id="icon-heart" viewBox="0 0 32 32" fill="currentColor">
<path d="M0 10 C0 6, 3 2, 8 2 C12 2, 15 5, 16 6 C17 5, 20 2, 24 2 C30 2, 32 6, 32 10 C32 18, 18 29, 16 30 C14 29, 0 18, 0 10 "></path>
</symbol>
<symbol id="icon-close" viewBox="0 0 32 32" fill="currentColor">
<path d="M4 8 L8 4 L16 12 L24 4 L28 8 L20 16 L28 24 L24 28 L16 20 L8 28 L4 24 L12 16 z "></path>
</symbol>
<symbol id="icon-hamburger" viewBox="0 0 32 32" fill="currentColor">
<path d="M3 8 A3 3 0 0 0 9 8 A3 3 0 0 0 3 8 M12 6 L28 6 L28 10 L12 10z M3 16 A3 3 0 0 0 9 16 A3 3 0 0 0 3 16 M12 14 L28 14 L28 18 L12 18z M3 24 A3 3 0 0 0 9 24 A3 3 0 0 0 3 24 M12 22 L28 22 L28 26 L12 26z "></path>
</symbol>
</defs>
</svg>
<h1>Progressive SVGs</h1>
<div class="buttons" data-codeblock>
<button aria-label="Like">
<span class="inline-svg" data-xlink="#icon-heart">♥</span>
</button>
<button aria-label="Close">
<span class="inline-svg" data-xlink="#icon-close">Close</span>
</button>
<button aria-label="Menu">
<span class="inline-svg" data-xlink="#icon-hamburger" >≡</span>
</button>
<p><a href="#">Do you <span class="inline-svg" data-xlink="#icon-heart" title="like">♥</span> me?</a></p>
<button aria-label="Like">
<span class="inline-svg" data-xlink="#icon-heart">♥</span> Like
</button>
</div>
## Working theory:
Most inline SVGs don't need fallbacks, they're icon candy paired with assistive text and/or they are decorative (like icon-fonts). This aims at **progressively enhancing critical fallbacks** when absolutely necessary. So, we take a span, with a little extra meta and replace it with an SVG `<use>` element when it appears enhanceable.
How it looks in IE8

## Approach
I try to scope the Image Replacement (IR) to either text or unicode. There are 5 examples here:
1. A Like `button` with a Unicode "BLACK HEART SUIT" (♥) fallback. This heart is generally supported. Added an `aria-label` on the `button` to avoid screenreaders stumbling on wonky Unicode. VoiceOver failed on reading SVG `title` attributes in a `button`.
1. A Close button with "Close" as a text fallback. The Unicode "MULTIPLICATION SIGN" (×) character has decent support, but I wanted an example where you might fall back to text. Same ARIA approach as above.
1. A Hamburger button with fallback Unicode "IDENTICAL TO" (≡) character. Same ARIA approach, but very necessary due to the desired label being "Menu" which is very different than the character's meaning.
1. A link with a Unicode heart (♥) fallback. Adding a `title` attribute here actually improved the accessibility for both SVG and fallback span.
1. A Like button with "Like" text. This doesn't really even require a fallback.
## Rules
- Use similar Unicode when you can get away with it.
- See [Unify](https://unicode.johnholtripley.co.uk/all/support) by John Ripley to guage how well a character is supported across devices and screenreaders.
- There's a bit of CSS you'll need to make sure old Windows uses 'Arial Unicode MS' as a fallback font with Unicode support.
- A lot of Zach Leatherman's [Bulletproof Icon Fonts](https://www.filamentgroup.com/lab/bulletproof_icon_fonts.html) applies here.
- Must be Accessible. Avoid wonky Unicode reading:
- Add `aria-label` to parent `button` elements.
- Use `title` attributes otherwise.
- If you used an external SVG (e.g., `some.svg#icon-hamburger`), you might be able to save legacy browsers the double download.
<small>SVGs from <a href="http://geomicons.com/">Geomicons</a></small>
View Compiled
// General Style
html, body {
background: #f0f0f0;
}
h1 {
text-align: center;
}
body {
font-family: sans-serif;
padding: 5%;
line-height: 1.6em;
}
img {
max-width: 100%;
height: auto;
}
.buttons {
text-align: center;
}
pre {
background: #fff;
padding: 1em;
max-height: 20em;
overflow: auto;
margin-bottom: 5%;
}
button {
font-size: 1em;
line-height: 1em;
}
// Inline SVG Code
// ====================================================
.inline-svg {
display: inline-block;
}
span.inline-svg {
// Unicode chars need a Unicode font on old browsers.
font-family: 'Arial Unicode MS', Arial, sans-serif;
}
svg.inline-svg {
// Tailor to suite your needs.
width: 1em;
height: 1em;
vertical-align: text-top;
}
View Compiled
(function(window, document){
// Feature Test
// TODO: Could be improved to detect INLINE only.
var supportsSvg = function(){
return document.implementation && document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image", "1.1");
};
// Enhance!
if(supportsSvg) {
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);
// 6 Minute Abs™, for your DOM.
span.remove();
}
}
})(window, document, undefined);
This Pen doesn't use any external CSS resources.