Generate custom icon fonts from SVG files
Icon fonts are a great way to add icons into your applications. Some of their main advantages — on top of the ones shared with SVG-file-based icons, like compact size and scalability — include:
- Ease of styling. In a web application, this can be done via CSS, just like any other font.
- All icons are packed into one file, meaning they can be downloaded within a single request, and they share a consistent look and feel.
- Straightforward implementation across different platforms.
In this post we’ll use FontCustom, a command line tool that uses FontForge in the background, to create our own icon font from a set of SVG files. Let’s get started!
Installation
The project’s repository README provides (outdated) instructions to get the code running. Here is my revised version for MacOS:
brew tap bramstein/webfonttools
brew install woff2 sfnt2woff eot-utils fontforge python-setuptools
sudo gem install fontcustom
Quick setup and results
In order to create our font, let’s first get ourselves some open-license SVG icons from SVG Repo. I’ve downloaded and placed them inside a folder icons/svgs
. I’ve also simplified the file names (e.g. to computer.svg
), as these will be used for the class names in our results.
All that’s left is to execute the command at the icons
folder location:
fontcustom compile svgs
We should get the following output:
By default, the tool generates font files in multiple formats, a CSS file defining the font face and classes for each of the icons matching the original SVG file names, and a preview html file:
/* /icons/fontcustom/fontcustom.css */
/*
Icon Font: fontcustom
*/
@font-face {
font-family: "fontcustom";
src: url("./fontcustom_e5ddb2182d5a3bce2aaa1d554376aea8.eot");
src: url("./fontcustom_e5ddb2182d5a3bce2aaa1d554376aea8.eot?#iefix") format("embedded-opentype"),
url("./fontcustom_e5ddb2182d5a3bce2aaa1d554376aea8.woff2") format("woff2"),
url("./fontcustom_e5ddb2182d5a3bce2aaa1d554376aea8.woff") format("woff"),
url("./fontcustom_e5ddb2182d5a3bce2aaa1d554376aea8.ttf") format("truetype"),
url("./fontcustom_e5ddb2182d5a3bce2aaa1d554376aea8.svg#fontcustom") format("svg");
font-weight: normal;
font-style: normal;
}
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: "fontcustom";
src: url("./fontcustom_e5ddb2182d5a3bce2aaa1d554376aea8.svg#fontcustom") format("svg");
}
}
[data-icon]:before { content: attr(data-icon); }
[data-icon]:before,
.icon-chip:before,
.icon-computer:before,
.icon-laptop:before {
display: inline-block;
font-family: "fontcustom";
font-style: normal;
font-weight: normal;
font-variant: normal;
line-height: 1;
text-decoration: inherit;
text-rendering: optimizeLegibility;
text-transform: none;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-smoothing: antialiased;
}
.icon-chip:before { content: "\f100"; }
.icon-computer:before { content: "\f101"; }
.icon-laptop:before { content: "\f104"; }
The CSS file contains everything we need to immediately start using the font on a web application. Pretty neat!
We can change the output file format to SCSS by adjusting the tool’s configuration options, and even provide a template to further customise what kind of files should be produced and what they should contain — we’ll take a quick look into it in our next section.
Note on SVG icons
If you are working with your own SVG files, make sure that you are not using any transparency nor clippings, for the conversion to succeed. Also, keep in mind that all colours will be projected to their corresponding grey scale, so you may want to use a grey palette yourself to have better control over the results.
Custom configuration
It’s possible to include multiple options as part of the compile command to adapt the results to a particular project. The full list of options can be consulted via:
fontcustom help
Alternatively, we can run
fontcustom config
to generate a blank YAML config file, which will be used every time fontcustom compile
is executed at this location.
Let’s extend our base example to create a SCSS file from a custom template and save the outputs in different destinations.
First, create a template file called _my-icons.scss
, under icons/templates
. I’ve taken the default SCSS template provided by FontCustom, and made some small modifications:
//
// Icon Font: <%= font_name %>
//
<%= font_face(path: @font_path_alt) %>
.my-icon {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
display: inline-block;
font-family: "my-icons";
font-style: normal;
font-weight: normal;
speak: none;
}
<%= glyphs %>
This should replace the whole middle section of our original CSS file above with a single .my-Icon
class selector and use a simpler styling.
Now, add a icons/fontcustom.yml
file with the following contents:
# =============================================================================
# Font Custom Configuration
# This file should live in the directory where you run `fontcustom compile`.
# For more info, visit <https://github.com/FontCustom/fontcustom>.
# =============================================================================
# -----------------------------------------------------------------------------
# Project Info
# -----------------------------------------------------------------------------
font_name: my-icons
css_selector: .my-icon--{{glyph}}
force: true
# -----------------------------------------------------------------------------
# Input / Output Locations
# -----------------------------------------------------------------------------
input:
vectors: svgs
templates: templates
output:
fonts: fonts
css: styles
templates:
- _my-icons.scss
preprocessor_path: /fonts
This configuration should:
- Rename our font to
my-icons
- Use
my-icon--
as prefix for all of our icon classes - Convert the SVG files located in the
svgs
folder - Regenerate all outputs every time, even if there haven’t been any changes in our SVG files
- Output the font files into a
fonts
folder - Use our
_my-icons.scss
template located under thetemplates
folder to produce a SCSS file, and save it under astyles
folder - Use global paths
/fonts
instead of relative ones when pointing to the generated font files
Let’s try it out by running
fontcustom compile
in the same location as before. Note that specifying the target svgs
folder is no longer necessary as it is already defined in our configuration. This returns:
Seems like everything was saved in the correct place, and all our modifications were applied into the SCSS file:
//
// Icon Font: my-icons
//
@font-face {
font-family: "my-icons";
src: url("/fonts/my-icons_c70af5a0f81b30ec59bd86dca7714971.eot");
src: url("/fonts/my-icons_c70af5a0f81b30ec59bd86dca7714971.eot?#iefix") format("embedded-opentype"),
url("/fonts/my-icons_c70af5a0f81b30ec59bd86dca7714971.woff2") format("woff2"),
url("/fonts/my-icons_c70af5a0f81b30ec59bd86dca7714971.woff") format("woff"),
url("/fonts/my-icons_c70af5a0f81b30ec59bd86dca7714971.ttf") format("truetype"),
url("/fonts/my-icons_c70af5a0f81b30ec59bd86dca7714971.svg#my-icons") format("svg");
font-weight: normal;
font-style: normal;
}
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: "my-icons";
src: url("/fonts/my-icons_c70af5a0f81b30ec59bd86dca7714971.svg#my-icons") format("svg");
}
}
.my-icon {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
display: inline-block;
font-family: "my-icons";
font-style: normal;
font-weight: normal;
speak: none;
}
.my-icon--chip:before { content: "\f100"; }
.my-icon--computer:before { content: "\f101"; }
.my-icon--laptop:before { content: "\f104"; }
Implementation
By importing the outputted CSS / SCSS file into a web project, we can make quick use of it by adding our my-icon
and the desired icon classes to a <i>
element:
<i class="my-icon my-icon--computer"></i>
<i class="my-icon my-icon--laptop"></i>
<i class="my-icon my-icon--chip"></i>
And style each icon via font-size
and color
css properties:
That’s pretty much it! I did mention it was straightforward in the list of benefits, didn’t I?
Final words
Despite working like a charm, the FontCustom project has seen virtually not activity in the last years. This might change eventually, with “recent” discussions about the future of the project — involving one of its authors — pointing towards turning the project over. Until then, 🤞.