Reducing the total Size of my blog
While looking at the size of the images and how long the take to load, I discovered, that the images were actually fine. The biggest offender in transfer time and size was actually the Material Symbols font files. The .woff2 file was around 3.2MB while the .ttf file clocked in 8.7MB. That is waaaaay too much for such a simple blog. I want to keep this blog as snappy and fast as possible without investing too much time. Images were an easy start, so I automated that in my my last blog post.
Now, I am using a pretty common resource here with the Material Symbols font. I want to host all dependencies myself, so I can at least try to prevent big CDNs or other orgs like Google to not get metadata about who is reading my blog just by loading a font or something like that. Requests to these dependencies should be cached for subsequent visits, but I also want the initial visit to be as snappy as possible. The font includes thousands of nice symbols for us to use. However, this blog really only uses five symbols in total: The light mode, dark mode, keyboard up, folder and label symbols.
If we somehow could cut the symbols we do not use and only focus on the ones we actually use, that would be awesome. Thankfully, there are ways to do that. This is called font subsetting. There are a bunch of web tools available to do that, CDNs also support that to reduce loading times. Further, the little python tool called fonttools also can do that. Even better, it can do it locally, in the command line ;D
Finding our codewords
First, we need to find the unicode values for the symbols we want to use. Those can be found in the github repository of the Material Symbols project. That results in the following codes for our symbols:
- folder: e2c7
- keyboard_arrow_up: e316
- light_mode: e518
- dark_mode: e51c
- label: e892
Armed with the unicode values, we can now cut out the fat from the
original ttf file using the fonttools subset function.
We also need to include the unicodes for a-Z, 0-9 and other commonly used
characters, so the browser can render a text if we missed one symbol.
Further, we can drop all advanced layout features like ligatures, kerning
and others with –no-layout-closure. We are only really interested in
symbols for stylistic reasons. To use the --flavor=woff2
feature, we
have to install python-brotli as an woff encoder as well. For backwards
compatibility reasons, we also generate a subset .ttf file.
echo "Creating woff2 subset"
fonttools subset MaterialSymbolsOutlined.ttf \
--unicodes=5f-7a,e2c7,e316,e518,e51c,e892 \
--no-layout-closure \
--flavor=woff2 \
--output-file=MaterialSymbolsOutlinedSubset.woff2
echo "Creating ttf subset"
fonttools subset MaterialSymbolsOutlined.ttf \
--unicodes=5f-7a,e2c7,e316,e518,e51c,e892 \
--no-layout-closure \
--output-file=MaterialSymbolsOutlinedSubset.ttf
Staying low
Cutting out the slack is a really substantial way to drop size. These two calls to fonttools reduced the ttf file from 8.7MB to 11kB and the .woff2 file from 3.2MB to 5.8kB. This huge drop lowers the total transfer under 1MB for each entire blog post, which is awesome! I really want to keep it as small as possible and this simple measure help loads.
Thanks for reading :)
Last modified on 2025-03-28