You could design an icon set where the icons all had the exact same aspect ratio. But that’s probably not typically going to be the case. The container around a little beaker icon might be tall and narrow. The container around a little fish perhaps short and long. You probably shouldn’t have to think too much about that, but unfortunately you kinda have to when you use an SVG icon system as I’ve described in the past, because you need to use the
viewBox attribute to describe that container/aspect ratio.
An improvement is to use the
<symbol> element in SVG instead of directly referencing shapes (or a
<g>), because you can define the
viewBox directly on the
<symbol> and then not need one when you
<use> it later in an
An example is in order.
Here’s two icons with very different aspect ratios, as you can tell from the artboard in Illustrator.
We could adjust them to all be placed within a consistent aspect ratio, but I find it’s more flexible and workable to know that your icons edges are right where the shapes stop, not with an arbitrary amount of white space around them.
The “Old” Way
If we go the
<defs>-block route, we might combine them into:
<svg> <defs> <g id="shape-icon-1"> <!-- all the paths and shapes and whatnot for this icon --> <g> <g id="shape-icon-2"> <!-- all the paths and shapes and whatnot for this icon --> <g> </defs> </svg>
Then use them like:
<!-- These viewBox's better be right or the icons won't look right! --> <svg class="icon" viewBox="214.7 0 182.6 792"> <use xlink:href="#shape-icon-1" /> </svg> <svg class="icon" viewBox="0 26 100 48"> <use xlink:href="#shape-icon-2" /> </svg>
That puts a good amount of onus on the implementer to get those
viewBox attributes correct in the markup. That’s one reason why might want to try and get all those icons at a consistent
viewBox="0 0 100 100" (or something), but then we have that kinda arbitrary whitespace thing going on.
The “New” Way
Enter Fabrice Weinberg and TxHawks. Fabrice works on grunt-svgstore, a Grunt plugin for creating the SVG sprites from a folder of SVG files. This kind of thing makes the SVG icon workflow quick and easy. That is, except for the fact that you need to know that dang
viewBox for each icon before you use it.
TxHawks suggested having grunt-svgstore at least put
data-* attributes on the
<g> elements that wrap each icon, so there could be programmatic access to what it is supposed to be. But unfortunately SVG doesn’t allow those (it would have probably worked, but might as well make a build tool spec-compliant). It doesn’t matter though, because soon after, they suggested using
<symbol> instead, which turns out to be quite a good idea.
Instead of using
<g> to wrap all the icon shapes, use
<symbol>, like this:
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="beaker" viewBox="214.7 0 182.6 792"> <!-- <path>s and whatever other shapes in here --> </symbol> <symbol id="shape-icon-2" viewBox="0 26 100 48"> <!-- <path>s and whatever other shapes in here --> </symbol> </svg>
Note that the viewBox is defined for each icon and as you’re defining it as opposed to when you’re using it. That means using it becomes easier:
<!-- We ain't even need no viewBox round here. --> <svg class="icon"> <use xlink:href="#shape-icon-1" /> </svg> <svg class="icon"> <use xlink:href="#shape-icon-2" /> </svg>
Easier, and less error prone.
And it gets better: you can add
<desc> tags in the symbol as well, meaning the accessibility stuff is baked in as you use it.
<symbol id="icon1" viewBox="original-file's-viewBox"> <title>original-file's-title</title> <desc>original-file's-desc</desc> <!-- <path>s and other shapes --> </symbol>
grunt-svgstore does this now, thanks to TxHawks and Fabrice!
Why <symbol> is better for icons
Just to put a point on it:
viewBoxcan be defined on the symbol, so you don’t need to use it in the markup (easier and less error prone).
desctags can be added within the
<symbol>and they kinda “come along for the ride” when the symbol gets used, making accessibility easier to do right.
- Symbols don’t display as you define them, so no need for a
- This is probably what
<symbol>was invented for anyway.