Wednesday 23 April 2014

Filled Under:

Injecting SVG With JavaScript

00:13:00

“Injecting SVG” – it sounds kinda complicated I know, but trust me it’s not. It’s actually super-simple! Right now you’re probably thinking “Why would you use JavaScript to inject SVG markup? What is it? And how does it work?” Let me explain.


Advantages of inline SVG

From a deployment point-of-view, there are so many ways of implementing SVG into your projects, each with their own pros and cons. However much of our implementation decisions come down to 3 all important variables:
• HTTP requests.
• CSS and JavaScript customisation capabilities.
• Browser support.
If you want to meet all 3 of these requirements (assuming IE 9+ support), it’s fair to say that using inline SVG <svg> markup is the way forward. It meets all these requirements pretty well (and you could use .png fallbacks for browsers that don’t support it).

Disadvantages of inline SVG

Inline SVG can get a little messy and bloat your document, particularly on larger projects. It can also be a little difficult to manage, especially if you’re using PHP or other modular workflows. For example, if you want to change something, you need to trawl through all your various bits and pieces, find the respective SVG markup, change it, save it, find the relative CSS, clear caches, etc etc…
Furthermore there are other issues with inline SVG like the inability to defer loading and the effect this may have on page-loading. Additionally, if you’re not caching your HTML/XML markup, none of the SVG markup gets cached by the browser.
In summary the disadvantages are as follows:
Bloats document.
• Caching issues.
• Future changes can be time-consuming.
No deferred loading capability.
• Can make modular workflows over-complicated.
• Markup is spread across entire document, not stored in one place.

Wow, that disadvantage list looks a whole lot bigger than the advantages list. Luckily we can use JavaScript to inject the SVG data, eliminating all those disadvantages while retaining the advantages of inline SVG. Here’s how it works.

Open your SVG code

Download your favourite icon, design your own or whatever SVG’s you work with. This can be in either .ai (Illustrator) or .SVG format or whatever format you work from – Basically whatever way you get from a visual vector-based editor to SVG markup code.
If you’re working from Illustrator (or working with an SVG file created by Illustrator), you’ll probably get something like this:
HTML
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="97px" height="97px" viewBox="0 0 97 97" style="enable-background:new 0 0 97 97;" xml:space="preserve">
<style type="text/css">
<![CDATA[
.my-circle{fill:#EC008C;}
]]>
</style>
<circle class="my-circle" cx="46.825" cy="48.016" r="32.954" blah blah blah.../>
</svg>
Quick-Tip: When saving as an SVG from Illustrator, click the “More Options” panel. Under the “CSS Properties” drop-down, select “Style Elements” then click “SVG Code“. This will automatically separate all the CSS styles from their elements, which you can then use in an external stylesheet.
seperating-SVG-CSS-with-Illustrator

Clean and minify that SVG

Once you’ve got your SVG markup, give it a clean up and minify the whole thing. There’s a code minifier here you could use. It should now look something like this:
HTML
<svg><circle class="mycircle" cx="46.825" cy="48.016" r="32.954" blah blah blah.../></svg>

Setup SVG-inject.js

Create a .js document and name it SVG-inject.js (or whatever else you want). First, cache a variable which will act as our target to inject the SVG into. Here I’ve used a unique ID as the variable. Then add an eventListener to check when the document has loaded.
Finally, paste your your SVG markup as the innerHTML content of that element. Note that if the SVG markup contains double quotation marks " ", it needs to be placed inside single quotation marks ' ' in JavaScript and vice versa.
Here’s how the basic function works:
JavaScript
var logo = document.getElementById("logo");

document.addEventListener('DOMContentLoaded', function(){

logo.innerHTML = 'SVG Code Goes Here';

});
Now, when we want our icon (logo) to appear all we need to do is create an element with the corresponding ID. Like this:
HTML
<span id="logo"></span>
JavaScript will then insert the SVG into that element when the document content has loaded.
See the Pen bAyps by Abhishek (@abhibagul) on CodePen.



Multiple Classes

The above example works on the notion that the target element is a unique ID, being only present once per document. However, you may need to inject the same SVG into multiple elements by class (e.g the same icon appearing multiple times on a page).
In this case the function would look like this:
JavaScript
document.addEventListener('DOMContentLoaded', function(){

var logo = document.querySelectorAll('.logo');

for (i = 0; i < logo.length; ++i) {

logo[i].innerHTML = 'SVG Code Goes Here';

}

});

Now any element that has the class .logo, will get the corresponding SVG markup injected as its contents.
See the Pen DoGzv by Abhishek (@abhibagul) on CodePen.



Multiple SVGs/Icons

Finally, if you’re working with a lot of SVG content (e.g icons), your SVG-inject.js file should look something like this:
JavaScript
document.addEventListener('DOMContentLoaded', function(){

var icon1 = document.querySelectorAll('.icon1');
var icon2 = document.querySelectorAll('.icon2');
var icon3 = document.querySelectorAll('.icon3');

//icon 1
for (i = 0; i < icon1.length; ++i) {
icon1[i].innerHTML = 'SVG Code Goes Here';
}

//icon 2
for (i = 0; i < icon2.length; ++i) {
icon2[i].innerHTML = 'SVG Code Goes Here';
}

// icon 3
for (i = 0; i < icon3.length; ++i) {
icon3[i].innerHTML = 'SVG Code Goes Here';
}

});

See the Pen bfudA by Abhishek (@abhibagul) on CodePen.



You can still customise with CSS and JavaScript

As I said at the start, one of the best aspects of using an SVG is the ability to customise things through both JavaScript and CSS. Here is an example using a toggle/click function on injected SVG markup:
See the Pen fndeL by Abhishek (@abhibagul) on CodePen.


Conclusion

Injecting SVG via JavaScript is a great solution, particularly if you want to defer the loading of your SVGs until after the page has loaded (or even after the window has loaded). Furthermore, doing it this way retains all the features that make SVG so dynamic to begin with (like custom CSS styling and JavaScript functions). Here are some of the advantages:
Doesn’t bloat document.
All SVG markup is stored in a single document.
Markup is stored in a .js file, which is highly cacheable.
• Future changes are easier.
Loading can be deferred.
• Makes sense for modular workflows.
Super easy to use – (e.g create a class to insert SVGs anywhere).
• All SVG markup remains inline within your documents.
SVG markup gets minified (quicker loading) / caching.
A single HTTP request for all your SVGs.
• CSS and JavaScript customisation is retained.
Decent legacy support (optional fallbacks for I.E < 9).
Optional ability to minify JS in addition to SVG.
Optional ability to Gzip JS in addition to minifying everything.

Future Ideas

If you’re working with grunt, it would be great if this kind of workflow could be implemented into a plugin. For example, something that listens to your SVG files, minifies them and creates the relevant .js injection – which you could then minify and place in a custom-scripts.js file. Maybe someone with some super-awesome grunt expertise could create one.

0 comments:

Post a Comment