Domain Specific Language

Font magic: Reducing the size of the web fonts I use

  1. Setting up a web font
  2. Emoji troubles
  3. Setting up a venv for fonttools
  4. Reducing the number of glyphs
  5. Results
  6. Final notes

I recently learned some new things about fonts! The good-looking variable EB Garamond font is almost one megabyte, but it contains a lot of glyphs that I don't need for this site. EB Garamond is going on a diet.

This was partially inspired by Cliffle's Making my website faster post, specifically the Reducing the cost of webfonts section. I say partially because when I first started using EB Garamond and Josefin Sans, I thought they were both way too big. I searched for some options on how to shrink them, but at the time I wasn't feeling inspired to use Python (Python is a bit... much, at times).

Setting up a web font

It's quite easy to set up web fonts, just download the ones you want, and then add them to your CSS file:

@font-face {
    font-family: 'EBGaramond';
    font-style: normal;
    font-weight: 400;
    src: url("/fonts/EBGaramond.ttf") format('truetype');
    unicode-range: U+0000-017F;
}

@font-face {
    font-family: 'JosefinSans';
    font-style: normal;
    font-weight: 600;
    src: url("/fonts/JosefinSans.ttf") format('truetype');
    unicode-range: U+0000-017F;
}

@font-face {
    font-family: 'Source Code Pro';
    font-style: normal;
    font-weight: auto;
    src: url("/fonts/SourceCodePro.ttf") format('truetype');
    unicode-range: U+0000-017F, U+2500-25FF;
}

html {
    font-family: "EBGaramond", serif;
}

.top-title {
    font-family: "JosefinSans", sans-serif;
}

code,
pre,
kbd {
    font-family: 'Source Code Pro', monospace;
    line-height: 100%;
    word-wrap: break-word;
}

Emoji troubles

The problem I found was that after applying EB Garamond, the emojis I was using around the site like these lovely flags 🇸🇪🇬🇧🇺🇸🇭🇷🇧🇦🇷🇸🇩🇪 just stopped working. Instead I saw emoji placeholders like "S E G B U S H R B H R S D E", if that makes sense. The browser was trying to find an emoji inside of EB Garamond, but EB Garamond doesn't seem to have any emojis.

To solve this, I had to select the unicode range I wanted to use from EB Garamond, and then fall back to serif or sans-serif for any other glyph, which is easy enough, just add the unicode-range propery of @font-face.

@font-face {
    font-family: 'EBGaramond';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("/fonts/EBGaramond.ttf") format('truetype');
    unicode-range: U+0000-017F;
}

I chose the range U+0000-017F because that's what I need. You can use the symbl.cc Unicode Character Table to find out which glyphs you might need. I chose Basic Latin, Latin-1 Supplement, and Latin Extended-A because together they cover the glyphs I use — the ones I need to spell my name — Erik Živković.

Setting up a venv for fonttools

For a Python non-believer like me this might actually be the hardest part.

My setup script py-setup.sh looks like this.

#!/bin/bash
python3 -m venv .venv
source .venv/bin/activate
pip3 install fonttools

Reducing the number of glyphs

To reduce the number of glyphs I ran this script, adapted from Cliffle's blog, that I call py-fixfonts.sh

#!/bin/bash
source .venv/bin/activate

pyftsubset \
    font-orig/EB_Garamond/EBGaramond-VariableFont_wght.ttf \
    --unicodes="U+0000-017F" \
    --ignore-missing-glyphs \
    --layout-features-=dnom,frac,numr \
    --output-file=static/fonts/EBGaramond.ttf

pyftsubset \
    font-orig/Josefin_Sans/JosefinSans-VariableFont_wght.ttf \
    --text="Domain Specific Language Front page · Blog · Photos" \
    --ignore-missing-glyphs \
    --layout-features-=dnom,frac,numr \
    --output-file=static/fonts/JosefinSans.ttf

pyftsubset \
    font-orig/SourceCodePro/TTF/SourceCodePro-Regular.ttf \
    --unicodes="U+0000-017F,U+2500-25FF" \
    --ignore-missing-glyphs \
    --layout-features-=dnom,frac,numr \
    --output-file=static/fonts/SourceCodePro.ttf

The Josefin Sans fonts is only used for the page title and the section links, so I tell pyftsubset to only keep the glyphs needed for exactly those texts.

Results

The table below says it all, size for the EB Garamond font was reduced to about 10% of its original size, and Josefin Sans too was reduced to a similar percentage of the original.

FontSize beforeSize After
EBGaramond-VariableFont_wght.ttf927 kB95 kB
JosefinSans-VariableFont_wght.ttf118 kB10 kB
SourceCodePro-Regular.ttf205 kB57 kB

Final notes

I assume the unicode-range property could be removed at this point, but I'll keep it around anyway, since I think it's cute.