While looking for custom fonts for this website, I came across Minlo, a minified version of the Apple system font Menlo.
I first thought it was made smaller by some cool compression technique. While that is true (converting to WOFF2 leads to smaller file sizes), I found that it even contains lesser characters (glyphs) than in a regular font file.
As I'd been considering using custom fonts in my website, I wanted to make something like Minlo, but for other fonts.
Manual approach
The first idea I had was to manually remove glyphs I don't need using Font Forge, a font editor.
I found a post that describes the exact same steps I tried - Create a custom font with only the glyphs you need. To summarize:
- Open a font file in FontForge
- Select glyphs you wish to remove and delete them
- Regenerate the font file
The process is straight-forward but time-consuming. Font files can have lots of glyphs, specifically any combination of characters from this List of unicode characters. There are also separate files for different weights, so the process became repetitive really quickly.
There had to be a way to do this programmatically, right?
Meet pyftsubset
I found an answer to this in the most unexpected of places - the FAQ section of Inter, a sans-serif font family.
The tool is called pyftsubset
, and since I'm looking for to create a file that contains a subset of the original set of glyphs, this sounds like the right one to go with!
Looking at the documentation, the tool is part of the fonttools
Python package, which I installed using pip
.
$ python3 -m pip install fonttools
$ pyftsubset -h
usage: pyftsubset font-file [glyph...] [--option=value]...
Try pyftsubset --help for more information.
Looking back at the docs, there are a couple of ways to provide which glyphs I want to keep. The easiest option seems to be using --unicodes
1, that takes a list of the Unicode code points (U+
followed by hexadecimal digits) representing each character.
If you're familiar with ASCII, Unicode (more specifically UTF-8) is another encoding standard that contains more characters than ASCII, like symbols and characters from other languages.
Demo time!
I created a subset file of the font Inter Regular, containing only uppercase and lowercase letters, digits and punctuation.
$ pyftsubset Inter-Regular.otf --unicodes=U+0020-007E \
--layout-features='' \
--passthrough-tables
The unicode range is from the Basic Latin unicode block, the --layout-features
flag is set to an empty string to remove all glyphs associated with OpenType features, while --passthrough-tables
skips over any sections of the file that the tool doesn't know what to do with.
With this, the file size has reduced from 591KB to 12KB, a 97% decrease!
$ du -Ahs Inter-Regular.otf Inter-Regular.subset.otf
591K Inter-Regular.otf
12K Inter-Regular.subset.otf
Converting the file to the WOFF2 format reduces the size further to 7.5KB!
$ pyftsubset Inter-Regular.otf --unicodes=U+0020-007E \
--layout-features='' \
--passthrough-tables \
--flavor=woff2
$ du -Ahs Inter-Regular.otf Inter-Regular.subset.woff2
591K Inter-Regular.otf
7.5K Inter-Regular.subset.woff2
This was pretty fun to experiment with, and after quite a lot of trial and error, I settled on a combination of Verdana for the text (same as before) and a custom subset of Menlo for code blocks.
Font trivia
While re-designing my blog, I found out more about the origins of Verdana and Menlo, and apparently they share common links to other fonts!
Verdana was the basis for the design of Bitstream Vera Sans. Bitstream Vera also has a monospaced font, which is what Menlo is based on.
Another common link is the DejaVu font family, an extension to the Bitstream Vera font family that adds support for more glyphs, which Menlo includes.
This explains why the two work well together!
Notes
-
I got confused for a bit on why the
unicodes
flag was displayed with one dash instead of two. This a bug in the docs, which has been discussed in fonttools#2900. ↩