Reducing Font File size with pyftsubset
Note: Since the publication of this article, I’ve switched to using the default Serif font instead of a Web font. Thus, some of the information in this article may be incorrect. I have left it up for posterity, though.
If you’ve read the ‘Tech Stack’ page of my website (linked in the footer), you will notice that I use two Web Fonts - Chomsky and Times Newer Roman. Rather than providing these fonts as links, I decided to download the OTF files and serve them along with the web page. Essentially, this means that the fonts on this website are sourced from files on my server. This post will cover how I reduced the size of these files in order to reduce load times and make my website lighter.
The Problem - Font Files are Big
A quick check shows that the original Chomsky OTF file is 128 kB. That’s not a lot, but given that I only use this font for the header of my site, it seemed a little excessive. The other font, Times Newer Roman, is just shy of 100 kB. This is more warranted, though, since I use it in the body of all my pages.
Initially, I thought the problem was unavoidable. “Surely”, I said, “if the smart people who designed this font figured out a way to make it smaller, they would have done so”. After some more research on this topic, I realized that font files are massive - not in terms of file size, but in terms of the characters they support. Chomsky, for example, contains Umlauts, Graves and other diactrics that are very useful if you write in a language that uses them. I do 99% of my writing in English, though, so I didn’t need these characters.
The Solution - Subsetting
While searching for a way to strip characters from a font file, I came across the process of subsetting. This essentially consists of taking a ‘subset’ of characters in a font file, and using this subset as a distinct file. The result is a smaller version of the file, that only contains the characters you need. This comes with a caveat - if you ever need to display a character that isn’t in the subset, even if you only use it once, you must generate a new font file.
Further research showed that there are other ways to reduce the size of a font file - This post by Iain Bean suggests using WOFF2 files instead of OTF files. My post only covers subsetting, though.
How to use pyftsubset
pyftsubset is a part of the fonttools Python library. It contains a number of tools to manipulate font files. It can be installed via pip:
pip install fonttools
After installing, you should have access to the pyftsubset command. This command takes in a font file, and the glyphs (AKA characters) to include in the subsetted version of the file. I found it most convenient to use Unicode (via the --unicodes option) to specify a range of glyphs. For example, if you want to include all characters in the Basic Latin Unicode Block, the command would look like this:
pyftsubset font_file.otf --unicodes="U+0000-007F" --output-file=font_file_stripped.otf
Reduction in Size
After subsetting my files, I found that the file sizes had gone down by more than 50%. In the case of Chomsky, the file size had gone from 128 kB to 45 kB. Quite the improvement, if you ask me!