grunt-webfont

Ultimate SVG to webfont converter for Grunt.

SVG to webfont converter for Grunt

Generate custom icon webfonts from SVG files via Grunt. Inspired by Font Custom.

This task will make all you need to use font-face icon on your website: font in all needed formats, CSS/Sass/LESS/Stylus and HTML demo page.

  • Works on Mac, Windows and Linux.
  • Very flexible.
  • Supports all web font formats: WOFF, WOFF2, EOT, TTF and SVG.
  • Semantic: uses Unicode private use area.
  • Cross-browser: IE8+.
  • BEM or Bootstrap output CSS style.
  • CSS preprocessors support.
  • Data:uri embedding.
  • Ligatures.
  • HTML preview.
  • Custom templates.

This plugin requires Grunt 0.4. Note that ttfautohint is optional, but your generated font will not be properly hinted if it’s not installed. And make sure you don’t use ttfautohint 0.97 because that version won’t work.

brew install ttfautohint fontforge --with-python
npm install grunt-webfont --save-dev

You may need to use sudo for brew, depending on your setup.

fontforge isn’t required for node engine (see below).

sudo apt-get install fontforge ttfautohint
npm install grunt-webfont --save-dev

fontforge isn’t required for the node engine (see below).

npm install grunt-webfont --save-dev

Then install ttfautohint (optional).

Then install fontforge.

  • Download and install fontforge.
  • Add C:\Program Files (x86)\FontForgeBuilds\bin to your PATH environment variable.

fontforge isn’t required for the node engine (see below).

There are two font rendering engines available. See also engine option below.

  • All features supported.
  • The best results.
  • You have to install fontforge.
  • Really weird bugs sometimes.
  • No external dependencies (except optional ttfautohint).
  • Works on all platforms.

Add somewhere in your Gruntfile.js:

grunt.loadNpmTasks('grunt-webfont');

Inside your Gruntfile.js file add a section named webfont. See Parameters section below for details.

Type: string|array

Glyphs list: SVG. String or array. Wildcards are supported.

Type: string

Directory for resulting files.

Type: string Default: dest value

Directory for resulting CSS files (if different than font directory).

All options should be inside options object:

webfont: {
icons: {
src: 'icons/*.svg',
dest: 'build/fonts',
options: {
...
}
}
}

Type: string Default: icons

Name of font and base name of font files.

Type: string Default: Same as font option

Filename for generated font files, you can add placeholders for the same data that gets passed to the template.

For example, to get the hash to be part of the filenames:

options: {
fontFilename: 'icons-{hash}'
}

Type: boolean Default: true

Append font file names with unique string to flush browser cache when you update your icons.

Type: string|array Default: 'font,icon'

List of styles to be added to CSS files: font (font-face declaration), icon (base .icon class), extra (extra stuff for Bootstrap (only for syntax = 'bootstrap').

Type: string|array Default: 'eot,woff,ttf', available: 'eot,woff2,woff,ttf,svg'

Font files types to generate.

Type: string|array Default: 'eot,woff,ttf,svg'

Order of @font-face’s src values in CSS file. (Only file types defined in types option will be generated.)

Type: string Default: bem

Icon classes syntax. bem for double class names: icon icon_awesome or bootstrap for single class names: icon-awesome.

Type: string Default: null

Custom CSS template path (see tasks/templates for some examples). Should be used instead of syntax. (You probably need to define htmlDemoTemplate option too.)

Template is a pair of CSS and JSON (optional) files with the same name.

For example, your Gruntfile:

options: {
template: 'my_templates/tmpl.css'
}

my_templates/tmpl.css:

@font-face {
font-family:"<%= fontBaseName %>";
...
}
...

my_templates/tmpl.json:

{
"baseClass": "icon",
"classPrefix": "icon_"
}

Some extra data is available for you in templates:

  • hash: a unique string to flush browser cache. Available even if hashes option is false.

  • fontRawSrcs: array of font-face’s src values not merged to a single line:

[
[
'url("icons.eot")'
],
[
'url("icons.eot?#iefix") format("embedded-opentype")',
'url("icons.woff") format("woff")',
'url("icons.ttf") format("truetype")'
]
]

Type: object Default: {}

Extends/overrides CSS template or syntax’s JSON file. Allows custom class names in default css templates.

options: {
templateOptions: {
baseClass: 'glyph-icon',
classPrefix: 'glyph_',
mixinPrefix: 'glyph-'
}
}

Type: string Default: 'css' or extension of template

Stylesheet type. Can be css, sass, scss, less... If sass or scss is used, _ will prefix the file (so it can be a used as a partial).

Type: string Default: null

Custom font path. Will be used instead of destCss in CSS file. Useful with CSS preprocessors.

Type: boolean Default: true

If true, an HTML file will be available (by default, in destCSS folder) to test the render.

Type: string Default: null

Custom demo HTML template path (see tasks/templates/demo.html for an example) (requires htmlDemo option to be true).

Type: string Default: fontBaseName value

Custom name for the demo HTML file (requires htmlDemo option to be true). Useful if you want to name the output something like index.html instead of the font name.

Type: string Default: destCss value

Custom demo HTML demo path (requires htmlDemo option to be true).

Type: string|array Default: false

If true embeds WOFF (only WOFF) file as data:uri.

IF ttf or woff or ttf,woff embeds TTF or/and WOFF file.

If there are more file types in types option they will be included as usual url(font.type) CSS links.

Type: boolean Default: false

If true the generated font files and stylesheets will be generated with opentype ligature features. The character sequences to be replaced by the ligatures are determined by the file name (without extension) of the original SVG.

For example, you have a heart icon in love.svg file. The HTML <h1>I <span class="ligature-icons">love</span> you!</h1> will be rendered as I ♥ you!.

Type: function Default: path.basename

You can use this function to change how file names translates to class names (the part after icon_ or icon-). By default it’s a name of a file.

For example you can group your icons into several folders and add folder name to class name:

options: {
renamefunction(name) {
// .icon_entypo-add, .icon_fontawesome-add, etc. 
return [path.basename(path.dirname(name)), path.basename(name)].join('-');
}
}

Type: boolean Default: false

If true task will not be ran. In example, you can skip task on Windows (becase of difficult installation):

options: {
skip: require('os').platform() === 'win32'
}

Type: string Default: fontforge

Font rendering engine: fontforge or node. See comparison in Available Engines section above.

Type: boolean Default: false

Adds IE7 support using a *zoom: expression() hack.

Type: integer Default: 0xF101

Starting codepoint used for the generated glyphs. Defaults to the start of the Unicode private use area.

Type: object Default: null

Specific codepoints to use for certain glyphs. Any glyphs not specified in the codepoints block will be given incremented as usual from the startCodepoint, skipping duplicates.

options: {
codepoints: {
single: 0xE001
}
}

Type: string Default: null

Uses and Saves the codepoint mapping by name to this file.

NOTE: will overwrite the set codepoints option.

Type: boolean Default: true

Enables font auto hinting using ttfautohint.

Type: number Default: 10e12

Setup SVG path rounding.

Type: number Default: 512

The output font height.

Type: number Default: 64

The font descent. The descent should be a positive value. The ascent formula is: ascent = fontHeight - descent.

Type: function Default: null

Allows for a callback to be called when the task has completed and passes in the filename of the generated font, an array of the various font types created, an array of all the glyphs created and the hash used to flush browser cache.

options: {
callbackfunction(filenametypesglyphshash) {
// ... 
}
}

Type: array Default: undefined

Allows for custom content to be generated and output in the same way as htmlDemo.

Each entry in customOutputs should be an object with the following parameters:

  • template - (string) the path to the underscore-template you wish to use.
  • dest - (string) the path to the destination where you want the resulting file to live.
  • context [optional] - (object) a hash of values to pass into the context of the template

At compile-time each template will have access to the same context as the compile-time environment of htmlDemoTemplate (as extended by the context object, if provided. See config-example below.

webfont: {
icons: {
src: 'icons/*.svg',
dest: 'build/fonts'
}
}
webfont: {
icons: {
src: 'icons/*.svg',
dest: 'build/fonts',
destCss: 'build/fonts/css',
options: {
font: 'ponies'
}
}
}
webfont: {
icons: {
src: 'icons/*.svg',
dest: 'build/fonts',
options: {
syntax: 'bem',
templateOptions: {
baseClass: 'glyph-icon',
classPrefix: 'glyph_',
mixinPrefix: 'glyph-'
}
}
}
}
webfont: {
icons: {
src: 'icons/*.svg',
dest: 'build/fonts',
destCss: 'build/styles',
options: {
stylesheet: 'styl',
relativeFontPath: '/build/fonts'
}
}
}
webfont: {
icons: {
src: 'icons/*.svg',
dest: 'build/fonts',
options: {
types: 'woff',
embed: true
}
}
}
webfont: {
icons: {
src: 'icons/*.svg',
dest: 'build/fonts',
options: {
customOutputs: [{
template: 'templates/icon-glyph-list-boilerplate.js',
dest: 'build/js/icon-glyph-list.js'
}, {
template: 'templates/icon-glyph-config-boilerplate.json',
dest: 'build/js/icon-glyphs.json'
}, {
template: 'templates/icon-web-home.html',
dest: 'build/',
context: {
homeHeading: 'Your Icon Font',
homeMessage: 'The following glyphs are available in this font:'
}
}]
}
}
}

We might then include the following corresponding templates.

The first, for icon-glyph-list-boilerplate.js, a file that outputs a list of icon-glyph slugs.

// file: icon-glyph-list-boilerplate.js
 
(function(window) {
'use strict';
 
var iconList = <%= JSON.stringify(glyphs) %>;
window.iconList = iconList;
}(this));

The second, for icon-glyph-config-boilerplate.json, a file that dumps all JSON data in the current template context.

// file: icon-glyph-config-boilerplate.json
 
<%= JSON.stringify(arguments[0], null, '\t') %>

And finally, the third, for icon-web-home.html, a file that has access to the values provided in the context object supplied.

// file: icon-web-home.html
 
<!DOCTYPE html>
<html class="no-js">
    <head>
        <meta charset="utf-8">
        <title>Context Test</title>
    </head>
    <body>
        <h1><%= homeHeading %></h1>
        <p><%= homeMessage %></p>
        <ul>
         <% for (var i = 0; i < glpyhs.length; i++) { %>
         <li><a href="#"><%= glyphs[i] %></a></li>
         <% } %>
        </ul>
    </body>
</html>

You can change CSS file syntax using stylesheet option (see above). It change file extension (so you can specify any) with some tweaks. Replace all comments with single line comments (which will be removed after compilation).

If stylesheet option is sass or scss, _ will prefix the file (so it can be a used as a partial).

If stylesheet option is less, regular CSS icon classes will be expanded with corresponding LESS mixins.

The LESS mixins then may be used like so:

.profile-button {
.icon-profile;
}

Firefox doesn’t allow cross-domain fonts: Specifications, Bugzilla Ticket, How to fix it.

  • Certain SVG's are not supported. See the svg2ttf project which is used to convert from SVG to TTF (which is then converted forward to WOFF and WOFF2).
  • autoHint also adjusts the font file and can cause your font to look different to the SVG, so you could try switching it off (though it may make windows view of the font worse).

Check the following...

  • Your paths are clockwise. Anti-clockwise paths may cause fills to occur differently.
  • Your paths are not overlapping. Overlapping paths will cause one of the areas to be inverted rather than combined. Use an editor to union your two paths together.
  • autoHint also adjusts the font file and can cause your font to look different to the SVG, so you could try switching it off (though it may make windows view of the font worse).

The changelog can be found on the Releases page.

The MIT License, see the included License.md file.