Creating an SVG icon workflow

A tutorial on how you can leverage all the fantastic benefits of an SVG based icon system whilst still providing support for those pesky older browsers.

The following post is a tutorial taken from the archived blog on my portfolio. If you're new to Assortment then welcome! This is my personal web development blog where I share practical tutorials and articles to help developers of all skill levels.

Lets get one thing straight; SVGs are pretty awesome. You only have to take a quicktriparound the Web to see the amazing possibilities it offers. One of these awesome features is its ability to create a pretty robust icon system for you. It's perfect and has everything you desire; you can scale them, stretch them, colour them and even animate them.

However, there's a catch. It's not supported in browsers (<IE8 and some older versions of Safari and Android). Life sucks, I know... but there's hope!

Before we get into how we can cope with this, lets take a step back and explain what this icon workflow provides and why it may be of use to you.

Pros

Simplicity: Export your icons from Illustrator or a website like Icomoon and stick them in a folder.

Inline SVG: You'll have access to edit the SVGs in the DOM. What does this mean? You can use fill: red in your CSS and it'll bloody work!

Support: IE8 and up, for all you unfortunate souls (me included). Its also very simple to take out the fallback when its no longer required.

Automatic Support: Automatically generated PNG's on the fly. Include the files are you're set.

On a side note, Chris Coyier's talk on SVGs is a must watch and he also has a blog post all about SVG icon systems. I'd encourage anyone wanting to get into the land of SVG and Icon systems to give them both a look.

Setting up the project

OK, lets get started on this abomination.

I'm going to be writing a lot of this in Command Line which some of you may not be so comfortable with... but don't run for the hills just yet. I'll break everything down into bite-sized chunks that'll hopefully be easier to digest. So, join me on this rollercoaster ride and let me explain the madness that rises in my noggin'. Who knows, maybe it'll be of some use to you?

Open up your Terminal.app/iTerm (I'd recommend downloading the latter) and create a folder you'll use for this project, then navigate to it.

$ mkdir ~/sites/svg-icon-workflow
$ cd ~/sites/svg-icon-workflow

As we'll be using Gulp to help automate a lot of our workflow, we need to initiate a new NPM (Node Package Manager) project.

$ npm init

And install all the required NPM packages, like so:

$ npm install —save-dev gulp gulp-svg-symbols gulp-svg2png

Done that? Awesome, now you should have a package.json within your project that looks similar to this:

There might be a few other bits and bobs in there, but as long as you have the above then you're good to go. Also, depending on when you're viewing this article could mean that the packages within the devDependencies section may have updated versions. Next we'll need to create our folder structure. Do this however you feel like, but using this as a basic:

If you're new to gulp or build tools, I suggest you take a look at someofthese tutorials to get you started. What I'm basically doing here is referencing the packages I need and assigning it to a variable (so that I don't have to write require(blabla) every time I want to use utilise a package.

PNG generator task

What have we done here? Well we've registered a gulp task called svg2png. This allows us to go into Command Line and type gulp svg2png, which will run any code within the annonymous function

Note: For info on anonymous functions and other syntax related do-dats, I'd recommend you give Eloquent Javascript a read. The online version is free.

Lets make our new task do something. Thinking logically about this, before we run the PNG generator, we need to define where the SVG files are located. Lets do that using the src() method. This'll sit within our anonymous function.

return gulp.src( 'assets/app/icons/**/*.svg' )

Now our task knows we want to use any .svg file within our assets/app/icons folder.

Note: If you ever see reference to * or **/* then thats called globbing. In this case it 'compiles' to "Hey machine, I'm looking for any files with an extension of .svg within my designated folder, no matter if they're in sub directories or not".

Next we want to run our svg2png package. On a new line, add the following

.pipe( svg2png() )

Now we need to tell our task where we want any response (new files in this case) from our task to be saved. Lets assign any response to our assets/dist/icons folder.

.pipe( gulp.dest( 'assets/dist/icons/png/' ) )

If you followed along you should now have a task that looks similar to the one below.

Here's a quick breakdown on what we've accomplished so far. First, we create our gulp task, which we can use by writing gulp svg2png into the terminal. Then, we've told our task where to look for our .svg files; followed by initialising our svg2png package on those files and sending the response (the new png files) to our assets/dist/icons folder.

Like with our svg2png task, we've defined our new task but within the squared brackets (array) is a list of any tasks you want to be run before this one starts. So in this case, if you run gulp sprites, gulp svg2png will be run automatically beforehand. Moving on, once again we'll define our source files which in this case are any icons within our assets/app/icons/ folder.

return gulp.src( 'assets/app/icons/**/*.svg' )

Now to run the svgSymbols package. This package allows us to configure the output a little through an object (the curly brackets).

.pipe(
svgSymbols({
className: '.icon--%f'
})
)

Thats it, we've now setup our Gulp tasks. Theres a few other tasks you'd want in a full Gulp build, for example watch and default tasks; but you can look into those elsewhere.

Using SVGs

Lets test our tasks are working now and look into how we'll use SVGs within our projects. Go ahead and create some SVGs in your assets/app/icons folder. You can export custom ones from Illustrator or drop them in from a system such as Icomoon or Fontello.

Note: As the PNG files are generated from your SVGs, so whatever the original size of your SVG is will be the size of your new PNG. As a tip when dealing with unsupported browsers, I'd recommend sizing your SVGs to be the size you'll be using them for. Try to come up with some set sizes to help with consistency, for example:

All your icons have been merged into a file at assets/dist/icons/svg-symbols.svg

Along with classes for each icon within assets/dist/icons/svg-symbols.css

PNGs have been generated within assets/dist/icons/png

All we need to do now is include the svg-symbols.svg within your HTML file. You could copy and paste this if you really wanted, but that'd mean c&p everytime you made a change to your icons and ran the gulp sprites task. Instead, I'd recommend you use a server-side include, for example, in PHP I'd do

<?php include("assets/dist/icons/svg-symbols.svg"); ?>

This must be just after the opening tag for < Chrome 37. You can read more on that here.

We're now ready to use our SVGs and tryout our cool little workflow-in-progress. Within your HTML file, write the following:

Note: Theres a lot of considerations you'll need to make with regards to making your SVGs accessible. I'd recommend you give Leonie Watson's post over on Sitepoint a read.

If you now view your element in the browser, you'll see it working. Try adding some some styling to it. fill: red; for starters. Maybe even a transform: rotate(160deg);. Its like magic.

Fallback automation

OK, so you now have an SVG workflow for modern browsers and we also have PNG files for each SVG. The only question that remains is how do we link the two? Well, I've already done that for you by creating a small script that you can add into your JS file. You'll want to add this file to the ending tag, or make sure that it loads after your SVGs.

Concluding thoughts

While theres quite a few steps to this process, I hope you'll agree that the result is worth it. I'm sure there are some better ways of accomplishing my goals; especially when it comes to the fallback script so please do leave feedback if you have any. Hope this helps a few of you out there.

This post is a tutorial taken from the archived blog on my portfolio. If you're new to Assortment then welcome! This is my personal web development blog where I share practical tutorials and articles to help developers of all skill levels.