Website developers have long used custom fonts to give projects individuality. Since these fonts aren’t built into operating systems, they need to be downloaded alongside the website.This makes both download speed and consistent display across different platforms crucial
Google Web Fonts is a popular example. This is a library of web-optimized fonts in WOFF2 format, which provides good compression.
But there are some nuances: a Google Web Font usually weighs 20-30 KB. If you use several styles and typefaces, you get 100-150 KB — a lot for a site. Another problem is a noticeable layout shift during page loading.
In this section, we will look at advanced techniques that will help speed up your site and improve UX when using web fonts.
Before diving into advanced techniques, let’s review the basic recommendations:
Ready for the next level? Here are a few tricks to help you reduce the size of your fonts, make them more appealing, and improve UX:
Important: Custom fonts not built into the operating system add extra load time. Since the browser doesn’t know the font’s parameters until it’s fully loaded, it initially uses a fallback font (like Arial or Times New Roman) to calculate element sizes. Once the custom font is loaded, the browser recalculates the sizes, which can cause a noticeable layout shift, especially on slower internet connections.
This example compares two fonts — Times New Roman and a custom font called Usual. Both fonts are 16px in size and have a line spacing of 1.2, but note the difference in the length of the same text.
Recently, new CSS properties have been widely adopted to help align the metrics of fallback and custom fonts:
This sounds great, but how do you set them up correctly? Katie Hempenius and Kara Erickson from the Google Aurora team developed an algorithm to address this, but automated solutions are needed to achieve the best results. The Next.js team recently announced support for these properties in the updated @next/font package in version 13. Our team took a similar approach and wrapped this algorithm in a CLI that generates CSS to customize the metrics of the fallback font; we called it Fontpie.
github.com/pixel-point/fontpie →
It’s very easy to use. Here is an example of a command:
npx fontpie ./roboto-regular.woff2 --name Roboto
Entering this command will return the following CSS that can be embedded in your project, no matter what framework or language you are using:
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('roboto-regular.woff2') format('woff2');
}
@font-face {
font-family: 'Roboto Fallback';
font-style: normal;
font-weight: 400;
src: local('Times New Roman');
ascent-override: 84.57%;
descent-override: 22.25%;
line-gap-override: 0%;
size-adjust: 109.71%;
}
html {
font-family: 'Roboto', 'Roboto Fallback';
}
To avoid layout shift when loading a custom font, we can adjust the size of the fallback font using CSS.
How it works:
1. We declare a new font (e.g. Roboto).
2. We declare another font (e.g. «Roboto Fallback») based on the local font (e.g. Times New Roman) and apply the main font metric settings to it. This completely eliminates layout shifts.
As you can see in the image, Times New Roman with metric settings now takes up the same amount of space as the Usual font.
This technique is compatible with all modern browsers except Safari.
Custom Character Set
This technique reduces the number of characters embedded in a font. Fonts usually contain many more characters than are needed for our project, so using a set that includes only the necessary characters can significantly reduce the font size.
Google Web Fonts provides a convenient API for creating font subsets. Consider the example of the Space Grotesk font. The size of the regular typeface (400) in WOFF2 format is 15 KB. The embedded link will look like this:
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk&display=swap" rel="stylesheet" />
To define a subset, just add the &text parameter to the URL. For example:
<link
href="https://fonts.googleapis.com/css2?family=Space+Grotesk&display=swap&text=HelloWorld"
rel="stylesheet"
/>
This is especially useful if we have a separate «stylish» heading that uses a different font compared to the rest of the site. In this case, we can define a subset that will include only the characters needed for this heading. In the example above, setting the subset reduced the font size to 1 KB.
If we use custom fonts (e.g. from Adobe Fonts), the task becomes more complicated. Many of them are not optimized for the web and contain many unnecessary characters, which can easily make their size reach 30 KB.
Font Squirrel is our assistant that allows you to easily create custom font subsets: just upload the font in TTF or OTF format, enable «Expert» mode and configure the subset.
Creating a subset is simple: we mark the necessary subsets or enter specific characters in the «Single Characters» field. For example, the © symbol is a subset of «Typographics», but if we only need it, we add it to the «Single Characters» field.
Another possible problem when using custom fonts (especially poorly optimized ones) is an incorrect vertical baseline. For example, in some fonts, the top margin may be smaller than the bottom, even if the same margins are specified in CSS.
Font Squirrel sometimes automatically fixes this problem. If not, use Custom Adjustments. Finding the right combination of metrics can take time, but it will solve the problem.
Capsize is a library that uses font metadata, allowing you to set the font size according to the height of uppercase letters, removing the space above them and below the baseline. It applies CSS rules with :before and :after pseudo-elements, adjusting margin-top and margin-bottom so that the text fits perfectly into the container and takes up all the space.
Example result:
// For 48px
.css-dpa7xb::before {
content: '';
margin-bottom: -0.1432em;
display: table;
}
.css-dpa7xb::after {
content: '';
margin-top: -0.2142em;
display: table;
}
// For 24px
.css-1m2jnlz::before {
content: '';
margin-bottom: -0.322em;
display: table;
}
.css-1m2jnlz::after {
content: '';
margin-top: -0.393em;
display: table;
}
This is a surprisingly easy-to-use solution that works 100% of the time.
We just need to add CSS code for each font size used on the page.
Tip: Try Font Squirrel auto-fixes first, and then, if necessary, connect Capsize.
Link to the original article — Advanced web font optimization techniques