Webfonts: Using Local Fonts as Source

When using either self-hosted or cloud hosted web fonts we can make small adjustments to the font definition in CSS that can decrease the first time page load of your site significantly. Instead of always loading the specified webfont, we can define either alternative fonts or the same font to load from the client system.

At the end of this post, there is a small utility to display all fonts on your system using Chrome.

The performance improvements for my blog for people who have the DejaVu font familiy installed is pretty good, on first load these fonts are loaded from disk instead of the network:

  • DejaVu Sans Bold: 351kB
  • DejaVu Serif: 212kB
  • DejaVu Sans: 380kB

Example of the DejaVu font combinations I use on this blog at the time of writing:

@font-face {
	font-family: 'DejaVu Serif';
	src: local('DejaVu Serif'),
		url('/fonts/DejaVuSerif.ttf') format('truetype');
	font-display: swap;
}

@font-face {
	font-family: 'DejaVu Bold';
	font-weight: 700;
	src: local('DejaVuSans-Bold'),
		url('/fonts/DejaVuSans-Bold.ttf') format('truetype');
	font-display: swap;
}

The line that can decrease the page load time for anyone with that font installed (mostly Linux users I guess), is this one:

  src: local('DejaVu Serif'),

Which tells the client system to first look for the local font, for which you can define an array. So if there are multiple variants you'd be okay with loading instead of requiring more bandwidth or if the font can have different names, you can specify multiple possibilities:

  src: local('DejaVu Serif', 'dejavu serif', 'DejaVuSerif'),

and so on.

This is about what I did until I found the correct name for the bold variant:

src: local('DejaVuSans-Bold'),
  url('/fonts/DejaVuSans-Bold.ttf') format('truetype');

Debugging Font-Loading

The easiest way to figure out when and if your font is loaded over the network is to open the browser Network tab and see if the request is made or when it's made to see if other content is prioritised when you define the swap rule.

chrome waterfall network graph

We want to eliminate this network request if possible, so if the user already has our font installed.

List Installed Font in the Browser

Finding the name of a font that you may want to substitute with a file already present on the client system can be a littly tricky, since this is a risk for people's privacy. Fingerprinting fonts is being used in the wild and there are other ways to do it by measuring the width of some rendered elements, but that's not what we're interested in here.

On MacOS you can also make use of Font Book to find the installed font, we're interested in the PostScript name

In Chrome on any platform, there is a Font permission API, so if you open the JavaScript console you can find the exact names with:

try {
  const availableFonts = await window.queryLocalFonts();
  for (const fontData of availableFonts) {
    console.log('postScriptName:',fontData.postscriptName);
    console.log('fullName:',fontData.fullName);
    // console.log(fontData.family);
    // console.log(fontData.style);
  }
} catch (err) {
  console.error(err.name, err.message);
}

after acknowledging a permission prompt.

font permission prompt

which will output a list:

fullName: DejaVu Serif
postScriptName: DejaVuSerif-Bold
fullName: DejaVu Serif Bold
postScriptName: DejaVuSerif-BoldItalic
fullName: DejaVu Serif Bold Italic

There are a few different values, we're going to take the postScriptName for DejaVu, because that's already installed on a lot of systems that use open office and a few Linux distros and this is how we use it in CSS:

@font-face {
  font-family: 'DejaVu Bold';
  /* this is the postScriptName value */
  src: local('DejaVuSans-Bold'),
    url('/fonts/DejaVuSans-Bold.ttf') format('truetype');
}

You can use the component below to see the fonts currently installed on your system listed by postscriptName, ready to use (in Chrome, Edge and Opera):

    Further Reading:

    Tagged with: #web performance #webfonts #CSS

    Thank you for reading! If you have any comments, additions or questions, please tweet or toot them at me!