I'm sure that plenty has been written on the minification of fonts, but it's something I thought I would write about given my learnings over the last few years.
If you can, choose system fonts. You will never have to worry about terms like FOIT or FOUT or take any hit on performance at all! Of course, that isn't always possible as typography plays a big part in the readability of a web page. However, should you be able to shirk the responsibilities of design, you can use system fonts.
- Serif: "Apple Garamond", "Baskerville", "Times New Roman", "Droid Serif", "Times","Source Serif Pro", serif;
- Mono: "SF Mono", "Monaco", "Inconsolata", "Fira Mono", "Droid Sans Mono", "Source Code Pro", monospace;
The above comes from this CSS Tricks article. Of course, it's possible to stray from these families - if you're into your typography; you can check out this opinionated article for a graded list of fonts you can use.
Next steps if you're wanting custom fonts is choosing the source. If you can use a free font, Google Fonts is a solid source. It gives you all the code you need, a will correctly load fonts with minimal impact on performance. Furthermore, if you're using a popular font, you can take comfort in the fact there is a chance a visitor may already have that cached.
I've not used many font providers, but I did find Adobe Typekit wasn't that great. Using their scripts, I frequently noticed FOIT - especially when testing on slow connections. I will generally request the TTF formats of fonts when I get given fonts from Adobe, in favour of hosting them via our own CDN.
If you opt to host fonts yourself (there is nothing wrong with this), you need to get the right formats. I will always opt for TTF, because I can use build tools to create the other formats I need which I will touch on soon. TTF is what I call a "source" font, in the fact it is bigger than other formats. This is a last ditch effort to cover older browsers with your font. In order of the formats I load, I use the following:
- woff2 (30% smaller than TTF)
I won't bother with OTF or SVG as the above cover all browsers. You can then use font-face to get the fonts to load in that order.
I spoke about opting to TTF fonts before, and now it's time for the reason - build tools. I'll be showing a way to do it with Gulp and then Webpack, but it will more than likely be possible to do it with other tools as well. There are two bits to this; formatting (as above) and filtering - that is removing the characters from font we are not going to use. This is really important as you're likely creating a site that's only going to in your language. For example, English isn't going to need Cyrillic or Japanese characters. This alone can reduce some fonts to a third of the size! If you need to support multiple character sets, check out my tricks below.
To do this in Gulp you will need to install the following:
Fontmin does most of the work, it sadly just doesn't do Woff2. You can then write the following script to take a "source" TTF font, and convert it as part of your build.
Using the original Fontmin, you can do the same as above. You will need:
Here some tricks to help get a little more out of your fonts.
When you strip back your character set and use woff2, you should find a very small file. I like to utilise this further and inline the woff2 font as base64 in my CSS. There are loads of tools for this, I use the post-css inline base-64 library. I wouldn't go crazy with this, but if you know you have some non-system fonts above the fold, this will ensure your font renders with your CSS.
You can preload fonts in your HTML and this can occur before the CSS is rendered. You can still use @font-face as normal.
<link rel="preload" href="/fonts/chinchilla.woff2" as="font">
Unicode Range Selector
You can expand on the build tools above, and break your fonts into multiple character sets. Once you have this, you can use the CSS unicode range descriptor. This descriptor goes into your font-face options and allows you to tell the browser what font-set matches a particular Unicode range. The browser will then decide if it needs that based on the characters it has in its document.
If you're having issues with FOIT, FOUT or FOFT you can use font-display to attempt to less then impact. This allows you to tell the browser how it should deal with the font.
When using @font-face, you don't just have to use url(). If you want a browser to try and get a font you think the system might have before it goes off into the web to get one, you can use local(). It's rare that you would want a specific font over a custom one, but it's just one extra tool to help you speed that font load up.
I'm by no means an expert. Fonts are complicated, even more so if you get on the topic of typography! If you're interested in reading more, here are some resources that helped me: