Go to main content
  • Johan Ronsse

Building a workflow to generate an icon font package

Last week, we released Mono Icons. This is a free icon set that consists out of 136 icons, that anyone can use in their projects. Our colleague Marina posted an article about the design of the icon set here.

This post dives into some technical details about the project: how we built the website, how we generated the icon font and an interesting technical gotcha we ran into.

The Mono Icons website is powered by Vue.js.

The site provides a search functionality, where we used fuse.js to provide a simple fuzzy search mechanism. On the website you can copy the individual SVG code for every icon. We used clipboard.js for this.

We used Vercel to deploy test versions while developing but eventually moved it over to our trusty own web host.

The project consists out of two code repositories. There is a website repo, which is a private repo at the moment, and an icon font repo which is public (Github link).

The icon font repo is also an npm package (npm link). Since every NPM package is also automatically hosted by the Unpkg CDN, this provides developers with a very simple way to reference Mono icons in small code examples like Codepens or Svelte REPLs: you can simply reference the stylesheet, like so:

<link rel="stylesheet" href="https://unpkg.com/mono-icons@1.0.5/iconfont/icons.css" >

This method is utilized in this Svelte REPL where all Mono icons are referenced, and where you can also see some example code to add icons in a way that a screen reader will still read out something sensible. 

Generating the icon font

To generate the icon font, we rely on the icon-font-generator npm package. This is a package we have been using in Bedrock for quite some time.

It transforms a folder of SVGs into an icon font, in all the formats you could want (SVG, eot, woff, woff2, ttf, otf etc.). 

We love icon fonts because you can deliver a lot of graphics variety with a single HTTP request. The woff2 file for Mono icons weighs in at just 9.26kb. Most modern browsers support the woff2 format and this will be the only file to be loaded. 

In our projects, we will typically ship a custom icon font that only uses the icons used in that project, making for the smallest file size possible.

One gotcha is that you have to set a specific height flag and value on the generator command, or else the icon font doesn’t render well:

icon-font-generator svg/*.svg -o iconfont --height 1000

For details, you can refer to this Github issue.

Publishing to npm

Currently, our proces for publishing to npm is rather manual. We bump the version number in package.json, and then run a sequence of commands like this:

cd ~/Sites/mono-icon-font
npm login
npm publish .

This then generates a tarball containing the package and publishes the new version to npm.

This is a copy/paste of the scripts section of our icon font package:

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "clean": "rimraf dist",
  "icon-font": "icon-font-generator svg/*.svg -o iconfont -p mi --height 1000",
  "prepare": "npm run clean && mkdirp iconfont && npm run icon-font",
  "start": "npm run clean && mkdirp iconfont && npm run icon-font"

It’s the prepare script that you need to be looking at: that’s the script that runs right before publishing.

That scripts generates a new build. The way it works in the background: npm-scripts provides different execution hooks as documented here. When you run npm publish, it runs whatever is in the “prepare” section first.

A weird Mobile Safari bug

So, right after we published the package, we found out it didn’t look good on Mobile safari. The icons rendered well in every browser we tested, except Mobile Safari.

It turns out that Safari was not handling overlapping SVG paths well. It’s a bit hard to explain but it has to do with how the browser renderer handles paths that run into each other.

It turns out that paths have a certain direction. When you construct a path in a vector editor, maybe you are drawing a square icon consisting out of 4 points, you might start on the top left, draw the top right point, then bottom right, then bottom left. So now you have drawn a clockwise path.

You could do it the other way around and draw a counter-clockwise path.

This is a simplified explanation, the actual explanation is more intricate, you can find details here.

It then turns out the directions of paths can affect the rendering of SVGs. In code form, the way an SVG graphic should deal with its paths is exposed as fill-rule="even-odd" (for clockwise paths) or fill-rule="non-zero" (for counter-clockwise paths).

It turns out Mobile Safari has quite poor support for clip-path-rule="even-odd" and struggles to properly render nested paths that use this SVG rule.

Figma plugin in action

The solution? To make sure your SVGs are using non-zero paths. Luckily, some smart people built a Figma plugin to change the fill rules on a path. On release day, our colleague Eva corrected all the paths.

A lot of technical details coming together

The reason I wrote this post is that it ties several technical details together: the publishing of an npm package, the publishing of an icon font, and the creation of a website to showcase said icon font.

I hope this helps some people on their way to create their own packages.

Johan Ronsse

About the author

Johan Ronsse is an interface designer who is trying to find the balance between aesthetics and usability. He tweets as @wolfr_2.

Subscribe to our newsletter

Receive blog highlights and fresh insights into UX/UI and front-end development.

Leave a comment

Your email address will not be published. Required fields are marked *