From my point of view SVG graphics are slowly gaining acceptance over icon fonts. The big advantage of SVG is that the rendering is the same across the browser, which is not guaranteed with fonts. The manipulation and animation possibilities are another big plus.
In this article I will first consider a workflow for automated SVG sprites for use as a background. The next article then deals with SVG sprites for inline use.
Preconditions
If you don’t have a clue about SVG yet, you should definitely read up on this complex topic at Chris and Sara.
You should also have worked with Grunt before.
Integration techniques
There are various approaches to the integration of vector graphics. At the moment I consider the following to be the most sensible ones:
symbols in a Strong>external/strong> referenced Strong>file
- Regular sprite for use in CSS background (background image)
- Symbols in an externally referenced file
- SVG completely inline (for complete manipulation with CSS and JavaScript)
Besides the image quality, the use of SVG should of course also improve the performance or at least keep it the same. To achieve this, SVG graphics should – if possible and reasonable – always be delivered as a collection (sprite or symbol collection). This saves HTTP requests. There are of course also use cases where a single graphic makes sense, e.g. the logo of a website.
In my description of the workflows I assume the following structure of the project directory:
root
|-- src
| |--img
| | |--heart.svg
| | |--shopping-cart.svg
| | |--...
| |--scss
|--dest
Global Setup
For automatic sprite generation I recommend the npm task grunt-svg-sprite for Grunt. In order to install the package, node.js must be installed.
- Switches to the project directory on the console cmd
- Make sure that a package.json is created there
- Install grunt-svg-sprite with the command npm install grunt-svg-sprite –save-dev
Regular SVG sprite for use in CSS background
A brief summary of this method:
- Use as background image: url(sprite.svg);
- The size of the container must have the same aspect ratio as the SVG
- A change in size is achieved by adjusting the background size
- The sprite graphic is cachebar
- The colours are not easy to manipulate
Configure Grunt Task
For this type of usage I use the following setting in the basic task:
svg_sprite: {
icons: {
expand: true,
cwd: 'src/img',
src: ['**/*.svg'],
dest: "./",
options: {
mode: {
css: {
bust: false,
dest: "dest/css",
sprite: "../img/icons.svg",
mixin: 'icons',
render: {
scss: {
dest: '../../src/scss/_sprite.scss',
template: 'src/scss/sprite.mustache'
}
}
}
}
}
}
}
As global destination folder I specify with ./ the reference to the basic file.js directory, so that the task can store the merged SVGs and the SCSS in different folders.
In addition to mode, the basic task has many other options, but these are not needed for our purposes for the time being. At least one mode must be specified for the task to work. In this case, the mode css generates an ordinary sprite, as we know it from times with PNG graphics. This is then generated in dest/img/icons.svgg.
In addition to the sprite we get CSS or SCSS code that contains ready-made classes or mixins that can be used to display the SVGs. The location is specified in the render.scss.dest option and is relative to the mode’s dest-directory.
Manipulate SCSS output
Unfortunately, the SCSS code that is provided by default is insufficient if you want to continue working with it efficiently. For example, the background size specification is missing completely, which makes scaling of the graphics impossible. The individual template, which can be specified in the form of a mustache template, provides a remedy here. In the template you have access to all necessary values of the SVG graphics. My mustache template looks like this
$icons: (
{{#shapes}}
"{{name}}": (
x: {{position.relative.x}}%,
y: {{position.relative.y}}%,
width: {{width.outer}},
height: {{height.outer}}
){{^last}},{{/last}}
{{/shapes}}
);
@mixin icon($name, $size: 100){
$sizeFactor: ($size / 100);
$targetWidth: {{spriteWidth}} * $sizeFactor;
$targetHeight: {{spriteHeight}} * $sizeFactor;
$icon: map-get($icons, $name);
background: url({{{sprite}}}) no-repeat;
background-position: map-get($icon, x) map-get($icon, y);
background-size: rem-calc($targetWidth $targetHeight);
width: rem-calc(map-get($icon, width) * $sizeFactor);
height: rem-calc(map-get($icon, height) * $sizeFactor);
}
This template generates a SCSS file which contains a map with all SVG meta data (position and size) and a mixin for integration as background graphic. As a convention I normalized all SVG graphics to 100 pixels width. So by specifying the size parameter you can specify a width in pixels to which the graphic should be scaled. The calculated pixel values are converted to the unit rem using the rem-calc function of Foundation. You don’t have to do this, but I highly recommend it. The conversion from px to rem can also be done with an own help function.
Use SVG sprite
After all the setup work we want to finally reap the rewards. To do this, we only need to partially integrate the generated _sprite.scss into our SCSS structure. This way we can easily create rules for the icons.
HTML
<i class="icon icon--heart-30"></i>
.icon{
&:after{
content: "";
display: inline-block;
vertical-align: middle;
}
}
.icon--heart-30{
&:after{
@include icon("heart", 30);
}
}
I use here the BEM notation for the variant of the icon which is in the text flow. Finally, we only address the mixin with the name (depending on the original file name) and the size of the desired icon.
The clou becomes clear as soon as you throw the next graphics into the folder and the basic task is optimally executed automatically by Watcher. Then you only have to duplicate one rule and adjust the selector and include.
The initial setup can be a bit laborious depending on the project structure, but productivity will increase if you know that many SVGs are used in the project. This workflow is definitely faster than maintaining a sprite manually. Also for the designers it is usually easier to provide single graphics than to organize a sprite.
Comments