In my website I use two typefaces Inter & Fira Code. The first font-family covers everything on this website except the code blocks.
My main pet peeve is that before Inter loads, the visitor will briefly notice a fallback font. This is pretty much inevitable unless:
- You use a loader (suboptimal)
- Your website transmits everything during the first connection roundtrip (~14K, sometimes impossible)
- You want to stick to the fallback font
But we'll work with what to have.
Other options
Using Google fonts
- Putting an external dependency on Google is not my cup of tea, privacy-wise
- You're not in control of the updates
- Since Chrome v86, cross-site resources like fonts can’t be shared on the same CDN. No performance boost using Google Fonts anymore
Using fonts from NPM
Like typefaces or fontsource.
- The fonts will be parsed by Webpack, will have a hash assigned to them breaking cache. There are workarounds but the alternatives are simpler
- You can’t preload the fonts easily
How to do it
1. Self-host the fonts
I like to manually fetch the desired fonts from the fountsource repo. By selecting the specific language subsets you need, you can trim a ~150kb font down to ~40kb, which is bonkers.
To avoid pulling multiple fonts, and since I don’t care for old browsers, I use the variable version of Inter & Fira Code (support), served as woff2.
/static
/fonts
- fira-code-var-latin.woff2
- inter-var-latin.woff2
2. Write the font declarations
And import the file from gatsby-browser.js
@font-face {
font-family: 'Fira Code';
font-style: normal;
font-display: swap;
font-weight: 300 700;
src: url('./fonts/fira-code-var-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
U+FEFF, U+FFFD;
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: swap;
src: url('/fonts/inter-var-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
U+FEFF, U+FFFD;
}
3. Preload the fonts
If you don’t have html.js
, check the process here. I prefer to only use react-helmet for properties that differ from page to page, so anything else lives in html.js
for me.
You'll notice that I don’t include Fira Code
here, as it’s not a critical resource.
<link
rel="preload"
href="/fonts/inter-var-latin.woff2"
as="font"
crossorigin="anonymous"
type="font/woff2"
/>
4. Cache them hard
I deploy my website in Netlify, and I use gatsby-plugin-netlify to handle any configuration.
Here’s how I cache my fonts, forever.
{
resolve: 'gatsby-plugin-netlify',
options: {
headers: {
'/fonts/*': [
'Cache-Control: public',
'Cache-Control: max-age=365000000',
'Cache-Control: immutable',
],
},
},
},
Otherwise, without the said plugin, a simple _headers
file in the public folder will suffice.
/fonts/*
Cache-Control: public
Cache-Control: max-age=365000000
Cache-Control: immutable
Fin
Before trying to install a font-related Gatsby plugin, why not consider this approach?
👋