Published at
Updated at
Reading time

I've been playing with variable fonts the other day and got excited about transitioning font weights without layout shifts.

But in the end, I had to conclude that a 785kB heavy variable font is too much for my lightweight blog. Especially, when I want to use this font only in a single demo component.

DevTools showing the 785bK weight of Roboto.

Nicolas Friedli pointed out that I can minimize the font's file size down to 322kB by using Glyphhanger — "the web font utility belt".

I've used Roboto and it includes 826 characters and 948 glyphs. That's a lot and my blog is English, so I'd use less than 10% of these provided characters.

Glyphhanger lets you remove all these unused characters and glyphs.

# subset Roboto to Latin character set
glyphhanger --subset=roboto.woff2 --format=woff2 --LATIN

By subsetting roboto.woff2 to the Latin character set, I cut the number of included font characters and the resulting file size into more than half!

Table showing how font subsetting reduces 826 characters to 234 which leads to a smaller font weight.

But after inspecting the subsetted font file with Wakamai Fondue, I discovered that I could probably squeeze out some more characters because I doubt I'll use any of these special characters either ÁÂÃÄÅÆÇÈÉ....

# subset Roboto to ASCII character set
glyphhanger --subset=roboto.woff2 --format=woff2 --US_ASCII

By choosing ASCII, I reduced the font to 95 characters and 121 glyphs, resulting in roughly 200kB. Success!

But now I was entering a dangerous territory because glyphs such as or had been excluded, too. I didn't want to add up with mixed or broken characters.

A sentence with broken unicode characters.

Luckily, Glyphhanger has a solution for this case, too. Use the --whitelist argument to include the ASCII character set and additional glyphs in your optimized font.

# include ASCII and custom characters
glyphhanger --subset=roboto.woff2 --format=woff2 --US_ASCII --whitelist=…“”

So far so good! But what if you really don't want to waste any bytes and only deliver the needed font characters? Glyphhanger also lets you specify a page, and then evaluates all the used characters to subset a perfect font that doesn't waste any bytes on the wire.

# print all used codepoints
glyphhanger --string
# !"#%'(),-./0123456789:;?@ABCEFGHIJLMNOPQRSTUVWXYabcdefghijklmnoprstuvwxyz{}©—

# print all used codepoints with a specific font
glyphhanger --family="Roboto"
# ,.DHIabcdefghiklmnoprstuvwy

# evaluate and subset font depending on used characters on a page
glyphhanger --subset=roboto.woff2 --family="Roboto"
# Subsetting roboto.woff2 to roboto-subset.woff2 (was 765.65 KB, now 56.54 KB)

All this automatic font subsetting is pretty wild, but it allowed me to squeeze as many bytes out of Roboto as possible.

Article component visualizing that the loaded font only includes the characters used.

My little article component that used Roboto to explain a relative font weight axis (GRAD) just got 700kB smaller by only including the characters in use!

I was even able to reduce its size down to 52kB by removing most of Roboto's font axes.

In conclusion: I highly underestimated how many bytes one can save by inspecting and subsetting fonts. The optimized Roboto variable font still includes all the custom axes and fancy variable font features, but especially for this single component, the page has become substantially lighter.

I'm still on the fence if I'll adopt custom fonts on this site, but this tool and trick are nothing but amazing!

Was this post helpful?
Yes? Cool! You might want to check out Web Weekly for more WebDev shenanigans. The last edition went out 4 days ago.
Stefan standing in the park in front of a green background

About Stefan Judis

Frontend nerd with over ten years of experience, freelance dev, "Today I Learned" blogger, conference speaker, and Open Source maintainer.

Related Topics

Related Articles