‘Reskinnable’ SVG Symbols: How to Make Them (..and Why)

Massimo Cassandro
Share

SVG symbols

The widespread adoption of SVG in modern web pages has really ramped in 2016 thanks to its, file size, scalability and CSS.

It can be used for icon systems (take a look at Build Your Own SVG Icons), although icon fonts, in some cases, can be preferable (some info here: The Great Icon Debate: Fonts Vs SVG).

But SVG can also be used for logos or graphic elements (at least not overly complex ones) and its natural flexibility makes it a perfect solution for responsive sites (take a look at Sara Soueidan’s Making SVGs Responsive with CSS).

The use of SVG makes it possible to target and change the size and color of an entire element through CSS, but, unless your SVG code is embedded in your HTML page, you can’t modify a single portion of it in this way.

The Problem

Let’s look at a simpler example. Here we have an image that we need to display in a range of colors.

Same SVG shape. Different colors.

Of course, traditionally we would simply create three standalone images – each with a different flavor. But what if we wanted to use a single SVG file and style it at render time?

Furthermore, is there a way we make our image a ‘SVG symbol’ to take advantage of browser caching?

I’m going to refer to this a “Reskinnable SVG symbol” – the “bones” of your SVG image remain the same but it’s easy to change the surface appearance.

The perfect solution would be accessing symbol elements through a CSS selector and add some rules to them (the same method that we would have used with embedded SVG).

In the following sample, I’ve added a class (top, right, bottom and left) to each triangle, arranged the image as a symbol and tried to modify it thru CSS, in this way:

.top { fill: #356BA5; }
.right { fill: #357FD9; }
/* and so on... */

Unfortunately, at the moment this only works with Firefox, as the following Codepen demonstrates. The second image appears in tones of blue only on Firefox (I’ve embedded the symbol code in the pen for convenience, but we have the same results with external SVG files).

See the Pen svg element editing (demo 1) by Massimo Cassandro (@massimo-cassandro) on CodePen.

See the Pen SVG CSS styling (demo 1) by Massimo Cassandro (@massimo-cassandro on CodePen.

In large projects, where we may have many elements like that, maintenance issues are an important factor, so I’m always searching for a way to better organize project assets.

My goal was a pure CSS solution: the previous sample can be rewritten using a single-triangle-SVG to be rotated, moved and colored using CSS.

But I didn’t like this solution: it seems to me that it simply moves the problem, without solving it. How many real-world logos have components that all have the same shape?

Sara Soueidan explains the problem much better then I do and offers us a clever solution using CSS variables. Unfortunately CSS variables are still an experimental technology and Microsoft browsers don’t support them.

The Solution

As it often happens, the solution is so head-slappingly simple that it will make you feel stupid for not having thought about it before.

I came across it looking at the new Medium logo some months ago (it seems Medium has since changed their logo code – you’ll have to take my word).

qJVnVmr

You can see that Medium logo consists of four ‘shapes’, each filled with a different flat color. The B&W version is identical to the green one (except for the colour, of course).

The solution for having a single file for both versions was to simply build a symbol for each shape, each of them within the same viewBox.

Let’s apply it to our example and create a symbol for each shape in our image. They all share the same viewBox of the whole image (0 0 54 54), so they place themselves in the right position without any additional instruction. Just take care to avoid fill, stroke, style etc. attributes in the symbol code).

<svg xmlns="https://www.w3.org/2000/svg">
	<symbol id="top" viewBox="0 0 54 54">
		<polygon points="54 0 0 0 27 27 54 0"></polygon>
	</symbol>
	<symbol id="right" viewBox="0 0 54 54">
		<polygon points="54 54 54 0 27 27 54 54"></polygon>
	</symbol>
	<symbol id="bottom" viewBox="0 0 54 54">
		<polygon points="0 54 54 54 27 27 0 54"></polygon>
	</symbol>
	<symbol id="left" viewBox="0 0 54 54">
		<polygon points="0 0 0 54 27 27 0 0"></polygon>
	</symbol>
</svg>

So now we can assemble them into a single SVG container:

<svg>
	<use class="top" xlink:href="#top"></use>
	<use class="right" xlink:href="#right"></use>
	<use class="bottom" xlink:href="#bottom"></use>
	<use class="left" xlink:href="#left"></use>
</svg>

Each use element can be styled however you like, and, most importantly, it is compatible with all modern browsers:

See the Pen SVG CSS styling (demo 2) by Massimo Cassandro (@massimo-cassandro on CodePen.

That’s all.

We just have to arrange our SVG files in this way. We can, of course, do it manually, but if you have to manage many graphic elements or you need to quickly edit and reuse them in more projects, you need a smarter and faster workflow. I’ve found my solution using Adobe Illustrator and a bit of Gulp.

SVG Symbols building workflow

The basics of this technique are the same I’ve just covered in my Build Your Own SVG Icons and Create an Icon Font Using Illustrator & IcoMoon articles, so take a look at them for the first steps.

Say we have two elements, just like in the image below. Each of them is arranged in a specific artboard:

Illustrator artboard

We gave them some color for convenience, although we know that the fill color (as well as, if there are any, the stroke one, the stroke size and so on) will be edited through CSS.

Since each symbol must have its artboard, we now have to split each image in as many artboards as each colored part.

This can be made very quickly in Illustrator, cutting each element, selecting the target artboard and choosing the Paste in place command.

Illustrator artboard

Note that each artboard has a specific name: it will be used for symbols IDs.

Now we can export our artboards to SVG using the brand new File → Exports → Export for screens command.

This is a really useful new tool of the latest Illustrator versions: it allows you to save each artboard or user-defined asset in many formats with a single command.

Choose “Artboards” from the export panel, set “SVG” as output format and select the destination folder:

Symbols exporting

Each artboards will be exported as a single SVG file:

SVG files

Now we need to put together all files as SVG symbols and to delete some SVG attributes we don’t need: a little gulp script will help us to do so very quickly.

Time for Gulp

The next section is slightly more technical, but – if you’re up for it – it will give you a fast, clean way to produce versatile SVGs like this.

I’ve already written about Gulp on SitePoint, and you can also find a lot of resources on the web about Gulp installing and all related arguments, so I’ll assume you’ve already installed it and that you know what we’re talking about.

Anyway, if you don’t like Gulp, you can also do all the following steps manually. I’ve done this many times before starting using Gulp: it is definitely a good way to learn and it’s more than enough in small projects or where a constant editing and maintenance work is not requested.

So, we have some SVG files, each of them is arranged just like the example below (the d attribute has been shortened for convenience):

<svg id="Layer_1" data-name="Layer 1" xmlns="https://www.w3.org/2000/svg" width="54" height="54" viewBox="0 0 54 54">
<title>umbrella-handle</title>
<path d="..." fill="#603813"></path>
</svg>

Our goal is to arrange all images as SVG symbols in a unique file while stripping away all the unwanted attributes:

<svg xmlns="https://www.w3.org/2000/svg">
	<symbol id="umbrella_handle" viewBox="0 0 54 54"> ... </symbol>
	<symbol id="umbrella_top" viewBox="0 0 54 54"> ... </symbol>
	<!-- and so on ... -->
</svg>

Beside Gulp, our job needs some other extensions:

  • First of all, gulp-svgstore and gulp-svgmin to combine and minify our svg files
  • gulp-rename to adjust id names and to give our destination files a specific name. This module is particulary needed if you want to use the previous Illustrator SVG export command, we’ll cover it later.

Now we can arrange our Gulpfile (the code is also available as a public Gist):

var gulp = require('gulp')
	,rename = require('gulp-rename')
	,svgstore = require('gulp-svgstore')
	,svgmin = require('gulp-svgmin')
;

gulp.task('default', function() {
	gulp.src(['svg_files/*.svg'])
		.pipe(rename(function (path) {
	        path.basename = path.basename.replace(/__icon_prefix__/, '');
	        return path;
	    }))
	    .pipe(svgmin(function (file) {
	        return {
		        // https://github.com/svg/svgo/tree/master/plugins
			    plugins: [
			    	{ cleanupIDs: { remove: true, minify: true } }
			    	, { removeDoctype: true }
			    	, { removeComments: true }
			    	, { removeStyleElement: true }
			    	, { removeDimensions: true }
			        , { cleanupNumericValues: { floatPrecision: 2  } }
			        , { removeAttrs: { attrs: ['(fill|stroke|class|style)', 'svg:(width|height)'] } }
			    ]
			    //,js2svg: { pretty: true } // uncomment for readability 
			};
	    }))
	    .pipe(svgstore())
    	.pipe( rename('my-icons.svg') )
    	.pipe(gulp.dest('./'));
});

After the modules are loaded, we indicate the files we want to parse (svg_files/*.svg).

SVGstore uses the name of each file to set the symbol id attributes (i.e. a file named umbrella.svg will become a symbol with id="umbrella"). If you are using the new Illustrator Export for screens panel, you can avoid the first rename command, since your files will be named exactly as the artboards they come.

But older versions of Illustrator create file names by concatenating the Illustrator file name with the artboard name, so we’ll need to rename files removing the Illustrator file name prefix:

path.basename = path.basename.replace(/__icon_prefix__/, '')

Now we can clean our files. gulp-svgmin is the Gulp version of SVGO a “Nodejs-based tool for optimizing SVG vector graphics files” (Jake Archibald released an online version of SVGO that is really useful if you want to arrange your files manually).

SVGO has a lot of configurable options (you can browse through all of them in the project page), but we are in need of just a few (you can, of course, customize the script according to your needs):

  • cleanupIDs: removes all ids from your files
  • removeDoctype, removeComments and removeStyleElement: strip all doctypes comments and <style> elements
  • removeDimensions removes all width and heights attributes if viewbox is present
  • cleanupNumericValues rounds numeric values to a sensible level of precision
  • removeAttrs removes all specified attributes

Next, the files are passed to svgstore to be combined in a unique file, which is then renamed and saved.

After using it a few times, you should be able to arrange it in a few minutes for each project, and it will give you the ability to quickly rebuild your SVG symbols file any time you need to.

This is an example of the result (even in this pen, I embedded the svg file for convenience, but you can safely link it as an external file):

See the Pen svg css styling (demo 3) by Massimo Cassandro (@massimo-cassandro) on CodePen.

Are there any caveats?

Since this method is based on styling use elements, we have problems when they are removed by a polyfill, as we see in svg4everybody.

In browsers that doesn’t support external symbols link (all IE), svg4everybody replaces all use elements with the content of the matching symbols. So all css rules that apply to use don’t take effect.

This can be solved adapting your CSS selectors to inner symbols element (path, circle, etc.), but it can be a little tricky.

Extra bonus

There are infinite variants of this workflow: you can deal with strokes, text, etc.

Another interesting feature to be explored is the use of Illustrator Symbols: they are exported as SVG symbols, and this opens up a lot of possibilities.

Illustrator Symbos in Bracket

Thanks for reading.