Creating your custom font kit (icon font)

Date
March 5, 2019
Hot topics 🔥
Marketing TrendsTech Insights
Contributor
Pavel Bazhenov
Creating your custom font kit (icon font)

Icons are everywhere. No matter how large or small your project is — there is always a need for icons. And sometimes it’s perfectly ok to use existing icons from a font kit. Especially when all that’s needed are commonly used icons. In big projects, you can end up dealing with hundreds of custom icons that are prepared by your designer. It so happened that I used to use some online services for generating custom icon fonts which actually allow you to create your own set quite quickly and simply. But it regularly caused a bunch of problems when it came time to support the existing set we had, the process was always irritating and painful.

Problem

Let’s imagine you need to add a new icon to your font, so you upload your SVG file to the service. Then you need to download a bundle with new font files and styles to replace the existing files in your project.

Sometimes you need to deal with already applied sets by other developers, in this case, you will need to first restore it by uploading an SVG file and then adding new icons. The worst part? You’ll need to repeat these steps every time you need to add a new icon. Surely there’s an easier way?

Solution

Now all you have to do to add a new icon is add a new SVG file to the appropriate folder and start npm run icons script – that’s it!

Let’s take a look at how it works under the hood:

I managed to find a great icon-font-generator, and all that you need to do is properly configure it. I really like it because it provides extra features which are required for my scope, like generating .json files and customising styles by using templates.

Script command in package.json file looks quite awkward:

"scripts": {
  "icons": "icon-font-generator src/assets/svgs/*.svg --normalize --center -o public/fonts --tag .icon  --name icon-font --csstp src/helpers/icon-font-template.hbs --csspath src/assets/styles/base/helpers/icons.scss --jsonpath src/helpers/icons.json --html false --fontspath /fonts/ --height 1000"
},

I will describe a little all parameters which I’m using here:

  • src/assets/svgs/*.svg define a path for your SVG files,
  • --normalizenormalizeyour icons size,
  • --centervertical alignment for your font,
  • --ooutput folder for generated font files,
  • --namejust a name for font files,
  • --csstpoutput path to a template for generating styles file,
  • --csspathoutput path for styles file,
  • --jsonpathoutput path for JSON file,
  • --htmlI don’t need a preview for my generated font so I set it to false,
  • --fontspathrelative path to fonts directory to use in output files,
  • --height I’ve set its value to 1000 and there is some trick here. It’s actually a solution for preventing rounding path in generated font symbols. I spend many hours to find it and without it, your icons can be look glitched and there is no good answer to how this magic works, I didn’t find an answer why it actually happens but it was discussed many times on StackOverflow and the solution that you need to set it to value about 1000.

There are other parameters in docs, you can configure.

Template for styles:

For generating styles files in icon-font-generator just grab a template which allows you to write your own styles according to your requirements. Below you can see my version, it’s quite straightforward. This icon-generator will use our previously described configuration to replace placeholders in a template and create a .scss file.

@font-face {
	font-family: "{{ fontName }}";
	src: {{{ src }}};
}

[class^="{{classPrefix}}"],
[class*=" {{classPrefix}}"],
.icon-font {
	line-height: 1;
	font-family: '{{ fontName }}' !important;
	font-style: normal;
	font-weight: normal !important;
	font-variant: normal;
	text-transform: none;
	line-height: 1;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

{{# each codepoints }}
.{{ ../classPrefix }}{{ @key }}:before {
  content: "\\{{ this }}";
}

I’m adding icon-font class because it’s very useful in cases where I can’t create an element with an appropriate class so I need to apply styles to an existing element, something like this:

.some-item {
  @extend .icon-font;
  @extend .icon-close;
}

You can see how the generated .scss file looks below:

font-face {
	font-family: "icon-font";
	src: url("/fonts/icon-font.eot?c5f00b38433312d2d8db1194230dee07?#iefix") format("embedded-opentype"),
  url("/fonts/icon-font.woff2?c5f00b38433312d2d8db1194230dee07") format("woff2"),
  url("/fonts/icon-font.woff?c5f00b38433312d2d8db1194230dee07") format("woff"),
  url("/fonts/icon-font.ttf?c5f00b38433312d2d8db1194230dee07") format("truetype"),
  url("/fonts/icon-font.svg?c5f00b38433312d2d8db1194230dee07#icon-font") format("svg");
}

[class^="icon-"],
[class*=" icon-"],
.icon-font {
	line-height: 1;
	font-family: 'icon-font' !important;
	font-style: normal;
	font-weight: normal !important;
	font-variant: normal;
	text-transform: none;
	line-height: 1;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

.icon-add-media:before {
  content: "\f102";
}
.icon-add:before {
  content: "\f104";
}
...

Bonus — JSON file for icons

You will notice that there is a parameter for a JSON file also. Why do you need it? Well, if you want to preview your generated icon font you can simply set HTML flag to true and in this case, the tool will generate the HTML file with all your icons.

I’m using a UI-elements demo page (I’ll write about it in a future article) where myself, our designer and other team members are able to see buttons, form elements and also icons. So I decided to use a JSON file to create a section for showing all icons in one place and also copying needed icon class-names. So a generated JSON file allows me to update changes in icons for this page automatically.

Below you can see what the component for icons looks like. I don’t think I need to explain much here, it’s pretty straightforward.

<template>
  <div>
    <h1>Icons</h1>
    <ul class="icons-set">
      <li v-for="(value, key) in icons" :key="key" @click="copyName(`icon-${key}`)">
        <i :class="`icon-${key}`"></i>
        <span>{{ key }}</span>
      </li>
    </ul>
  </div>
</template>

<script>
  import { copyToClipboard } from '@/helpers/utils';
  const icons = require('@/helpers/icons.json');
  export default {
    name: 'icons-section',
    data() {
      return {
        icons,
      };
    },
    methods: {
      copyName(value) {
        copyToClipboard(value);
        this.$store.commit('SHOW_MESSAGE', { type: 'success', title: value, text: 'Copied to clipboard ?' });
      },
    },
  };
</script>

Conclusion

So if I need to add a new icon I just paste it in the folder where the other SVG files are located, or delete the needed icon and start npm run icons command in my CLI. Now the process of managing icons becomes more transparent for all team members.

It takes a few seconds to do all the work and in my case, I see changes immediately with hot-reload.

Pavel Bazhenov

Pavel is one of our front-end wizards, or as he says it, an implementer of really cool designs for WeAreBrain and our clients. His secret skill: take broken things and bring them back to life.

Working Machines

An executive’s guide to AI and Intelligent Automation. Working Machines takes a look at how the renewed vigour for the development of Artificial Intelligence and Intelligent Automation technology has begun to change how businesses operate.