Adding a web font
Post #13 published on by Tobias Fedder
I added a web font, in my on‑going effort to gradually — and apparently very slowly — turn this site into something that I myself can respect. Now before you tell me that the type looks extremely familiar, let me point out that there is a chance that you aren’t seeing it right now. Unless you’ve visited this site already after I’ve added the font and you still have it cached.
That’s because I decided against delaying showing the text for the font to load; in other words I chose to go with font-display: optional;
. Until now font-family: system-ui;
, spitting out whatever font your operating system deemed acceptable, has been good enough. So why make you wait? Just so I can make a desperate attempt at expressing my tone for this site through a type family — sometimes somewhat serious but expressly not dry (instead of dry, I first thought of not boring, but whom am I kidding)?
The type family is called Geologica, at least that is what it’s called on Google Fonts where I found it more than two years ago while looking for variable fonts. When analyzed via wakamaifondue.com it’s name is shown as Geologica Thin instead 🤷, which is kinda weird considering its bulkiness. The fact that it’s been that long ago, and I haven’t found another type family that I think is more fitting in the meantime, makes me somewhat confident in that decision. Besides the classic axes weight and slant, this variable font allows to toggle cursive glyphs — limited to the characters a and g, at least as far as I can tell — and it has an axis for sharpness, giving the impression that small parts of the characters are cut off, resulting in sharp edges.
Font subsetting
The ZIP file I downloaded contains one variable font, as well as classic fonts containing typefaces with fixed weights and slants, all of them are in the True Type Font (TTF) format. I’m only interested in the variable font — in case someone’s user‐agent doesn’t support variable fonts, system-ui
will be good enough once again. That file is large though, 336 KB.
Luckily I knew that there are other font formats and I remembered that font subsetting is a thing. It is a method to create a font that only contains a subset of the glyphs and features, leaving out the parts that are unnecessary in the context the resulting font should be used in.
Remembering that a method exists and knowing how to execute it are two different things. A little bit of searching led me to barrd’s post Create a variable font subset for smaller file size. The post explains how to use the pyftsubset
command from the Python package fonttools, to subset a font in terms of unicode ranges and features, and how to change the font format.
In order to use it I had to install it first. Subsetting a font isn’t something I see myself doing every week, so I decided against installing it globally or integrating it in the build. Instead I created a virtual environment inside of my git repository. I left a README.md
and a requirements.txt
for my future self, as well as a .gitignore
to exclude the files of the virtual environment.
cd ./utils/font-optimizing python -m venv ./venv source ./venv/bin/activate pip install fonttools brotli pip freeze > requirements.txt
As long as that virtual environment is active I can run pyftsubset
. At frist I held on to all characters and features, only changing the format to the modern Web Open Font Format 2 (WOFF2).
pyftsubset Geologica-VariableFont_CRSV,SHRP,slnt,wght.ttf \ --unicodes="*" \ --layout-features="*" \ --flavor="woff2" \ --output-file="Geologica-based-subsetted-VF-v1.woff2"
That worked. I’ve modified a font. At that point I had a second look at the font license. The Open Font License (OFL) in version 1.1 allows for modifying fonts, but if it has a Reserved Font Name (RFN), then the modified font needs to be renamed. The copyright notice revealed that Geologica isn’t a RFN. Therefore I still don’t know how to edit a font’s name or font log.
The output file is a lot smaller, around a third of the TTF, just 113 KB. It still felt a bit heavy though. It was time to pick groups of characters worth holding on to. I started with the unicode ranges from barrd’s post and adjusted them to my needs. I ended up with the following command.
pyftsubset Geologica-VariableFont_CRSV,SHRP,slnt,wght.ttf \ --unicodes="U+000D-00FF, \ U+1E9E, \ U+2000-206F, \ U+2070-209F, \ U+20AC, \ U+2100-214F, \ U+2190-21BB, \ U+2200-22FF, \ U+FB00-FB06" \ --layout-features="*" \ --flavor="woff2" \ --output-file="Geologica-based-subsetted-VF-v1.woff2"
The first range also marks the first deviation from barrd’s choice, extending the range beyond Basic Latin, almost like adding the eighth bit to ASCII, so it includes Latin-1 Supplement. Which gives me all the umlauts I need for my German writing. It also includes the two currency symbols £ and ¥ as well as other niceties.
Another currency, too young to have a symbol in the earliest unicode blocks, is the €; that’s code point U+20AC
. Speaking of young characters, even the capital letter sharp s (ẞ) — basically useless outside of German signage, don’t worry about it — found its way into that font; therefore code point U+1E9E
.
Given that a niche symbol like that is considered in that type, it is somewhat damning that the interrobang is missing. An important punctuation mark near and dear to my heart. So important in fact, that I assumed I use it all the time.
Checking my assumption showed that I’ve used it twice on this whole site. Just twice‽ Okay, thrice, so it’s a big deal; system-ui
to the rescue! The other thing I’m missing is the thin space (U+2009
), and, I guess because of that, the narrow no-break space (U+202F
) as well.
The remaining ranges I copied from barrd’s post are general punctuation (U+2000-206F
), superscripts and subscripts (U+2070-209F
), letterlike symbols (U+2100-214F
), arrows (U+2190-21BB
), mathematical operators (U+2200-22FF
), and ligatures (U+FB00-FB06
).
The file was down to 46 KB. At this point removing the layout feature for displaying fractions, which I’m not too excited about, didn’t move the needle much. So I left it there in favor of simplicity. Finally, what I thought of — very mistakenly — as the hard part was done. I just needed to copy it in my assets
directory and reference it in my CSS. That can’t be that hard, right?
Using a variable font with CSS
Okay, so let’s use that font.
:root {
font-family: "Geologica", system-ui;
}
And for that to work I had to specify the font.
@font-face {
font-family: "Geologica";
src:
url("/assets/fonts/Geologica-based-subsetted-VF-v1.woff2")
format(woff2)
tech(variations);
font-display: optional;
}
And there it was, my draft of this blog post presented in a web font of my choice in my Firefox. Quick check in a Blink browser: nope, still system-ui
.
It took me way more minutes to understand what was happening than I like to admit. I wasted time looking for typos and syntax errors in my CSS, that I thought Gecko was handling more gracefully.
But the CSS was working exactly as I suggested. So far I have all the CSS inlined in the <head>
and the browser was done processing it before the dev server sent the font. Blink did as I said and skipped the optional web font. I started a web server with my configuration locally and verified that it worked as intended — falling back on system-ui
without the font in the cache, showing Geologica otherwise.
Then, looking at the letters in the context of my blog, the bulkiness of the regular weight was too much for the paragraphs. I played around with the font-weight
and found values between 300 and 330 felt right. But there was a problem. The system-ui
fonts on the devices I tried were too light at 300. So I picked font-weight: 350;
as a compromise.
After getting the boldness under control I made the headings a bit more fun by setting Geologica’s sharpness axis to the max.
main > :is(h2, h3, h4) {
⋮
font-variation-settings: 'CRSV' 1, 'SHRP' 100;
}
While taking in the result of that, I took a closer look at the Blink browser and saw a few words and characters that caught my eye. It looked like they were falling over.
Feature or faux pas?
I am not going to pretend, that I have an eye for typography to the extend that I look at some slanted glyphs on a random web page and go: That text is obviously in faux italic — disgusting!
In case that you don’t know what I’m talking about: faux bold or faux italic text is a compromise the browser makes when it is tasked to present text bold or italicised, but misses a font for that. The browser then uses an algorithm to distort the regular font, giving it a bold or oblique appearance.
But what was happening — so that even I noticed — was that the Blink browsers used the −12° slant available as an axis in the variable font and then faux italicised it by algorithmically slanting it another −12°. font-synthesis: none;
stops browsers from doing this in general.
Oh, poor browser thinks it’s missing a font. Maybe I should tell it that the font is already there.
, I thought. I added a second font descriptor referencing the same font, using the same name. And I told it that the second one’s style is italic using certain variation settings.
@font-face {
font-family: "Geologica";
src:
url("/assets/fonts/Geologica-based-subsetted-VF-v1.woff2")
format(woff2)
tech(variations);
font-style: italic;
font-display: optional;
font-variation-settings: 'CRSV' 1, 'slnt' -12;
}
Double slant gone, great. In Firefox it even used the cursive glyphs for a and g, not in my Blink browsers though. So I added some CSS for <em>
.
em {
font-variation-settings:'CRSV' 1;
}
For some reason it stays slanted that way. I was under the impression that all variation settings have to be repeated to not be removed. The above mentioned Wakamai Fondue generates handy utility classes to deal with that, for that very reason.
Yeah, I just wanted to add a web font. I’m left confused and at this point I’m hoping any visible text shows up in WebKit at all. Please let me know.
Addendum: The slant was missing in WebKit, it’s supposed to be:
em {
font-variation-settings:'CRSV' 1, 'slnt' -12;
}
Thanks for reaching out.