I love using Iosevka. I use it absolutely everywhere, in my editors, my terminal, as a UI font, and even on this website. The only issue is that, even when using the compressed woff2 version, it is absolutely massive and makes up 95% of my total page size!
Given woff2 is already the most optimal version of a font to use on the web, I had to figure out what was taking so much space.
Anatomy of a font
It might be easy to think of a font file as just containing a character set, in either a bitmap or vector format. However, it turns out that fonts contain so much more metadata than just the characters it supports.
An example of extra metadata in some formats is font hinting, which is a set of instructions added to a font which tell the computer how to resize and render it at lower resolutions. Such additional information like hinting, kerning, or ligatures may not be necessary and can provide space for further optimisation.
A particular area I looked into for Iosevka is simply the number of characters it supports. As of writing, it supports 226 languages, has 6,000+ Unicode characters, and 36,000+ glyphs to represent said characters. This is frankly a ridiculous number of extra glyphs which I am never going to need on this website, and thus a good place to start to reduce file sizes.
Removing unwanted characters
The Python library fonttools is capable of altering fonts, and one of its features is the ability to subset fonts. To do this, you need to download the TrueType (ttf) versions of the font in question. One particular thing to look out for is to only download the necessary styles. The browser can do a good enough job at rendering fonts in italics or bold based on a regular style, but if design accuracy is important then this might not be a good idea. For Iosevka, I only downloaded the regular and semibold styles.
Next is to decide a range to subset fonts. Unicode has definitions for over 100,000+ characters now, the vast majority of which are completely unneseccary. symbl.cc is a good website which shows the ranges of each block, with basic ASCII range being U+000-007F.
I used the range 0+000-55F, which covers Latin and the Greek symbols, and compressed the font back to woff2.
The final result is a reduction of 96% (from the original 1.2MB woff), simply by removing unused styles and subsetting the specific character sets.
@font-face
Another optimisation to be made is the way fonts are defined. Some visitors may already have a font installed locally, especially if it's a particular programming font, so it is possible to skip the network step entirely and use their font by using local
.
Any font styles not explicitly defined in the above style sheet will be generated on the fly by the browser, which may vary in quality, but is generally good enough for me.