Variable fonts aren't universally supported
I make a lot of webpages. I also use Lockdown Mode on iOS and MacOS for a bit of extra security. Sometimes I realize that I forgot to test on Safari and it looks like crap, or I test and don’t notice that there’s been a problem for months (as was the case with this blog).
Regardless I’ve now resolved the same problem like 5 times in the last few months and I always forget how I resolved it (mainly because it’s quite subtle), so I figured writing this down will help me and hopefully help you (or your AI agent) too.
The issue and the fix
In Safari (both iOS and desktop), Lockdown Mode disables variable fonts, setting every axis to its default.
Works everywhere except Lockdown Safari:
<link href="https://fonts.googleapis.com/css2?family=Lora:wght@400..700&display=swap" rel="stylesheet">
Fortunately Google Fonts seems to have provided an escape hatch: if you request a single weight of a variable-weight font, you get that single weight on its own without the variable axes. And Safari is perfectly happy to render non-variable fonts. So to work around this bug, just specify a separate <link> element for each separate weight:
The Workaround:
<link href="https://fonts.googleapis.com/css2?family=Lora:wght@400&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Lora:wght@500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Lora:wght@600&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Lora:wght@700&display=swap" rel="stylesheet">
Yes this is slightly annoying: everyone now needs to download four files instead of one file from Google Fonts. This shouldn’t make much of a performance impact in practice, but it’s not nothing either.
What’s Lockdown Mode?
Lockdown Mode, an Apple feature on their desktop and mobile platforms, is a defense-in-depth operating system setting which reduces your attack surface while using the platform. It disables a bunch of features for security, especially around processing user-generated content like web pages and text messages. Fonts are apparently one of these areas where Lockdown Mode imposes limitations.
What are variable weight fonts?
A variable font is a single file containing a whole continuous range of weights (and sometimes width, slant, optical size) in one. Each glyph is a little program that interpolates across all the variable axes provided by the font designer. That little program is an attack surface, so Lockdown Mode turns it off.
Variable fonts have been supported by browsers since 2018 or so, so it makes sense that Google Fonts would default to using it.
Why this is so rare
First, Lockdown mode is a rare setting. Apple nudges you away from using it.
Secondly, fonts still render, they just render slightly wrong. Most people aren’t that attuned to typography and so they just won’t notice.
Third, most fonts aren’t variable fonts. There are a good number of them on Google Fonts today, but the vast majority of fonts have designer-specified widths, which have no issue in Lockdown Safari.
Fourth, most variable fonts have a default weight that is somewhat sensible.
I got quite lucky to notice it: I tried to use my Lockdown Mode iPhone to show a friend my web page, which used Source Sans 3 as its body font. This particular variable font defaults to a weight of 200, which is very light and was nearly unreadable on my phone. But most fonts’ default weight is 400 or so and then the effect is much more subtle—simply a lack of boldface, which is easy to miss on a quick skim and users aren’t that likely to complain.
Can I just specify the exact weights in one request?
If you know about Google Fonts, you know it has specific syntax for requesting multiple separate weights vs. a range.
But sadly this doesn’t work either. Google happily serves the same variable font (presumably a static file on their end) whether your request says wght@400;600;700 (specified weights) or wght@400..700 (the range). You only get the special behavior if you specifically request a single weight.
If you’re not using Google Fonts
You need to pre-bake variable fonts into individual weight files and serve those font files separately.