Using Google Fonts properly
How and why I have chosen to use Google Fonts.
What happened to variable fonts?
In this post I wrote that I wanted to experiment with variable fonts. After looking online for a good open source variable font, I found the one I wanted to use on my website: Source Sans.
The problem is that I couldn't find a light variable version of Source Sans
in woff2
, so the entire loaded font weighted 123kb
. Compared to 2 non-variable font files in woff2
, which weight 26kb
combined, and since I'm only using 2 font-weight
s: 300 and 400 so far. Using non-variable fonts seems to be the way to go.
To host or not to host (the custom fonts)
The answer to this question is not binary. But in our case, taking advantage of a CDN for our fonts has multiple advantages:
- we don't have to optimize the fonts for each browser
- there's a good chance that the font file is already cached by the user's browser, which will reduce the load time.
That is why I decided to use the Google Fonts CDN to import Source Sans Pro
into my website.
The CDN already supports HTTP/2 and uses gzip so we don't have to handle that.
FOUT or FOIT?
FOUT
stands for Flash of Unstyled Text
. It describes the effect you have before your custom font is loaded and the browser display your text content with the first available font in your font-family
declaration.
FOIT
stands for Flash of Invisible Text
. This strategy hides the text completely before the custom font is loaded.
Based on your preference, you can use font-display: block;
to have FOIT
or font-display: swap;
to have FOUT
.
The font-display css property needs to be set when declaring the @font-face
. Which would be annoying for our choice of using Google Fonts, because the @font-face
is provided by the CDN.
The good news is that Google Fonts recently allowed us to specify a custom font-display
in the css URL.
By importing:
<link
href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400&display=swap"
rel="stylesheet"
/>
we are now able to force FOUT
with a local font that matches the best our custom font.
Preconnect
Having dynamic fonts loaded specifically for the client is great but it comes with a cost: a DNS lookup, a TLS negotiation and a TCP handshake. We can use preconnect
to anticipate the need for those.
At first I tried to add dns-prefetch
and preconnect
to the domain fonts.gstatic.com
. I realized that dns-prefetch
was not needed in my case since preconnect
also does the lookup.
dns-prefetch
performs a DNS lookup ahead of time.preconnect
performs DNS lookups, TLS negotiations and TCP handshakes before the HTTP request is made.
This is the code I added in <head>
:
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin />
This allows my fonts to be loaded faster since the entire connection to the server is done as soon as the <head>
is parsed.
Before without preconnect:
After with preconnect:
Notes about react-snap
While trying to optimize the way the Google Fonts were loaded I noticed that, in production, I had no calls to https://fonts.googleapis.com/ and the 2 fonts downloaded were .ttf
files which weighted each around 21kb
(!).
The reason for that is react-snap
and inlineCSS: true
. Since react-snap
downloaded all the css files for me in order to inline them, and since it's chrome doesn't seem to have the "latest" headers for font files, Google Fonts was loading .ttf
files as fallback.
I removed inlineCSS: true
from the react-snap
configuration and now the font files loaded are woff2
files, which are around 13kb
each.
While inlining the css file from Google Fonts speeds up the page load, it does not load the most optimized font file type for the current client.
Notes about unicode-range subsetting
If you look into a Google Fonts generated css, you'll see that every subset is there. The file is actually ready for all non-latin languages.
Since I my website will only contain latin characters I don't need other subset.
Google Fonts doesn't support adding &subset=latin
in their api URL for browsers which supports unicode-range subsetting, which is now pretty well supported:
The browser actually use this line to figure out what font it should load or not:
unicode-range: U+1F00-1FFF;
While I wanted to optimize every bit of the css that is loaded onto my website, being able to use cached fonts still makes using Google Fonts the better option for me, for now.
The code for the changes I'm mentioning in this post is available on Github in this Pull Request.