In the first part of this series, I've attempted to compare self-hosting Google fonts with having them provided by Google. My personal winner was the former option and this article describes how to implement it.
Recapitulation: DIY or CDN?
In a nutshell: Should you host your own fonts?
- Are you serving your website to European citizens and don't want all that additional GDPR hassle (user consent, an extensive privacy policy, legal notes, ... you name it)?
- Do you want more control over your served content? And do you feel confident to adjust some configuration on your server?
- Would you like to rely less on the big player's infrastructure to serve critical files? Or are you tired of consultants and lawyers telling you to do so?
If you find yourself among these three, you are likely a good candidate.
Download the fonts you would like to self-host
For the following steps, I'll assume you have the following project structure.
/
| - fonts/
| - styles/
| | - main.css
| - index.html
- Head over to https://fonts.google.com/ and select your favorite font(s)
- Click on 'Download family' and confirm the download
- Save the downloaded file in your project folder
- Unzip the directory.
You will now have a variety of .ttf
files available. Each of these files represents a specific font style
You can achieve even better results using Google fonts helper. It provides you more modern formats with fallback options & CSS snippets.
Add the font-face rules to your CSS
Now that we have the fonts available, we must configure them in our styles. This is done by using the @font-face rule.
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: url('../fonts/Roboto-Regular.ttf');
font-display: swap;
}
You can then start applying the font-family
as you usually would:
.custom-font {
font-family: 'Roboto', 'sans-serif'
}
Next, apply the class custom-font
to your HTML. Notice how the style, followed by the font file, is then loaded into the browser:
So far so good, but there are still some improvements to be made here. Google still does some important things for us, some of which are:
- Providing browser-specific font types
- Taking care of preloading fonts without blocking the browser
- Setting the correct headers for cache control
We can, however, set these features up ourselves, so let's go ahead and do that
Get the browser-specific - version of your font
Google's CDN automatically serves you the font format that is supported by your browser. And while the .ttf
file from earlier works, .woff
formatted fonts are served faster and supported by all modern browsers.
Using the Google fonts helper app saves you a bit of manual labor here.
Fortunately, there's a simple trick to figure the correct font to download. Let's take Roboto as an example again.
- Head to the browser you require the fonts for (or use a browser simulator like Browserling)
- Parse the URL you found on Google fonts and navigate to it
- You will find a CSS file that has the optimal
@font-face
CSS rules for your browser
Some examples for other font formats and browsers using them are
- Chromium-based Browsers & Firefox | Font Type
.woff2
https://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Mu72xKOzY.woff2 - Internet Explorer 10/11 | Font Type
.woff
https://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Me5g.woff - Safari 4 | Font Type
.tff
https://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Me5Q.tt
After downloading the font and replacing the source URL in the main.css
file, everything still looks as expected:
Configure your app to preload fonts
By default, loading CSS happens synchronously and thereby blocks the browser's rendering process. This also includes our @font-face
CSS rules. Before rendering text, the browser must first load the necessary fonts. This takes time and is bothersome for users. Luckily, it is also fairly simple to circumvent.
With this approach, textual content is rendered before the fonts are available. Then, once loaded, they're applied - the fonts are swapped.
In your index.html
:
- Instead of requesting the CSS file that deals with fonts with
rel="stylesheet"
, add therel="preload"
andas=font
attributes - Then, use the
window.onload
event to overwrite therel
attribute once the HTML is done loading
<!-- Replace -->
<link rel="stylesheet" href="./styles/main.css">
<!-- With -->
<link rel="preload" as="font" href="./styles/main.css" onload="this.onload=null;this.rel='stylesheet'">
This trick alone boosted my lighthouse score by an unbelievable amount of 8%
Configure your server to send a cache header
To demonstrate this, I use Nginx v1.18 on a 5$ Digital Ocean Droplet:
- SSH into your droplet with
ssh root@<ip-adress>
- Open the default Nginx server config
nano /etc/nginx/sites-endabled/default/
- Add the following wildcard rule right above the first
location
to apply a cache of 30 days (=2592000 seconds) for static assets
# Set cache headers for all css and font files
# This header can also be extended for other static content
location ~* \.(css|ttf|woff|woff2) {
add_header Pragma public;
add_header Cache-control "public max-age=2592000";
}
# location / { ... }
- Use
systemctl reload nginx
to gracefully restart Nginx - Move your files to the droplet using Linux'
scp
or, alternatively, Filezilla
# Copy the whole directory to the droplet
# Note that I am using /test/ as a path instead of just /
# as scp recursively copies the whole folder structure
scp -r <path-to-project>/test/ root@<droplet-ip>:/var/www/html/
Once that is done, try and access your droplet by its IP address. You should see something like this:
If you made it here in one piece (especially if you've read the bit about data privacy), you're now the proud owner of a website with its own instance of Google Fonts.
Further reading & resources
There are more excellent projects and articles on the internet that deal with this topic.
- Using a web framework? Use 'Fontsource' to install fonts with npm: https://fontsource.org/docs/introduction
- The cost of moving from Google Fonts to self-hosted web fonts: https://jeremenichelli.io/2020/07/google-fonts-self-host-web-fonts/
- A list of popular Google Fonts pairings: https://www.w3schools.com/howto/howto_google_fonts_pairings.asp