In the previous modules, you learned how to optimize of HTML, CSS, JavaScript, and media resources. In this module, discover some methods to optimize web fonts.
Web fonts can impact page performance at both load time and rendering time.
Large font files can take a while to download and negatively affect First
Contentful Paint (FCP), while the incorrect font-display
value could cause
undesirable layout shifts that contribute to a page's Cumulative Layout Shift
(CLS).
Before optimizing web fonts can be discussed, knowing how they're discovered by the browser can be helpful, so that you can understand how CSS prevents the retrieval of unnecessary web fonts in certain situations.
Discovery
A page's web fonts are defined in a style sheet using a @font-face
declaration:
@font-face {
font-family: "Open Sans";
src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2");
}
The preceding code snippet defines a font-family
named "Open Sans"
, and
tells the browser where to find the respective web font resource. To conserve
bandwidth, the browser does not download the web font until it is determined
that the current page's layout needs it.
h1 {
font-family: "Open Sans";
}
In the preceding CSS snippet, the browser downloads the "Open Sans"
font file
as it parses an <h1>
element in the page's HTML.
preload
If your @font-face
declarations are defined in an external style sheet, the
browser can only begin downloading them after it has downloaded the style sheet.
This makes web fonts late-discovered resources—but there are ways to help the
browser discover web fonts sooner.
You can initiate an early request for web font resources by using the preload
directive. The preload
directive makes web fonts discoverable early during
page load, and the browser immediately begins downloading them without waiting
for the style sheet to finish downloading and parsing. The preload
directive
does not wait until the font is needed on the page.
<!-- The `crossorigin` attribute is required for fonts—even
self-hosted ones, as fonts are considered CORS resources. -->
<link rel="preload" as="font" href="/fonts/OpenSans-Regular-webfont.woff2" crossorigin>
Inline @font-face
declarations
You can make fonts discoverable earlier during page load by inlining
render-blocking CSS—including the @font-face
declarations—in the <head>
of
your HTML using the <style>
element. In this case, the browser discovers
web fonts earlier in the page load, as it does not need to wait for an external
style sheet to download.
Inlining @font-face
declarations has an advantage over using the preload
hint, as the browser only downloads the fonts necessary to render the current
page. This eliminates the risk of downloading unused fonts.
Download
After discovering web fonts and ensuring they are needed by the current page's layout, the browser can download them. The number of web fonts, their encoding, and their file size can significantly affect how quickly a web font is downloaded and rendered by the browser.
Self-host your web fonts
Web fonts can be served through third-party services, such as Google Fonts, or can be self-hosted on your origin. When using a third-party service, your web page needs to open a connection to the provider's domain before it can start downloading the needed web fonts. This can delay discovery and subsequent downloading of web fonts.
This overhead can be reduced using the preconnect
resource hint. By using
preconnect
, you can tell the browser to open a connection to the cross-origin
sooner than the browser ordinarily would:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
The preceding HTML snippet hints the browser to establish a connection to
fonts.googleapis.com
and a CORS connection to fonts.gstatic.com
. Some
font providers—such as Google Fonts—serve CSS and font resources from different
origins.
You can eliminate the need for a third-party connection by self-hosting your web fonts. In most cases, self-hosting web fonts is faster than downloading them from a cross-origin. If you plan on self-hosting web fonts, check that your site is using a Content Delivery Network (CDN), HTTP/2 or HTTP/3, and sets the correct caching headers for the web fonts you need for your website.
Use WOFF2—and WOFF2 only
WOFF2 enjoys wide browser support and the best compression—up to 30% better than WOFF. The reduced file size leads to quicker download times. The WOFF2 format is often the only one needed for full compatibility across modern browsers.
Subset your web fonts
Web fonts typically include a wide range of different glyphs, which are needed to represent the wide variety of characters used in different languages. If your page serves content in only one language—or uses a single alphabet—then you can reduce the size of your web fonts through subsetting. This often done by specifying a number—or a range of—unicode code points.
A subset is a reduced set of the glyphs that were included in the original web font file. For example, instead of serving all glyphs, your page might serve a specific subset for Latin characters. Depending on the subset needed, removing glyphs can significantly reduce the size of a font file.
Some web font providers—such as Google Fonts—offer subsets automatically through
the use of a query string parameter. For example, the
https://fonts.googleapis.com/css?family=Roboto&subset=latin
URL serves a
style sheet with the Roboto web font that only use the Latin alphabet.
If you've decided to self-host your web fonts, the next step is to generate and host those subsets yourself using tools such as glyphanger or subfont.
However, if you don't have the capacity to self-host your own web fonts, you can
subset web fonts provided by Google Fonts by specifying an additional text
query string parameter containing only the unicode code points necessary for
your website. For example, if you have a display web font on your site that only
needs a small number of characters needed for the phrase "Welcome", you can
request that subset through Google Fonts through the following URL:
https://fonts.googleapis.com/css?family=Monoton&text=Welcome
. This can
significantly reduce the amount of web font data needed for a single typeface
on your website, if such extreme subsetting can be useful on your website.
Font rendering
After the browser has discovered and downloaded a web font, it can then be
rendered. By default, the browser blocks the rendering of any text that uses a
web font until the it's downloaded. You can adjust the browser's text rendering
behavior, and configure what text should be shown—or not shown—until the web
font has fully loaded using the font-display
CSS property.
block
The default value for font-display
is block
. With block
, the browser
blocks the rendering of any text that uses the specified web font. Different
browsers behave slightly differently. Chromium and Firefox block rendering for
up to a maximum of 3 seconds before using a fallback. Safari blocks indefinitely
until the web font has loaded.
swap
swap
is the most widely used font-display
value. swap
does not block
rendering, and shows the text immediately in a fallback before swapping in the
specified web font. This lets you show your content immediately without waiting
for the web font to download.
However, the downside of swap
is that it causes a layout shift if the fallback
web font and the web font specified in your CSS varies greatly in terms of line
height, kerning, and other font metrics. This can affect your website's CLS if
you don't take care to use preload
hint to load a web font resource as soon as
possible, or if you don't consider other font-display
values.
fallback
The fallback
value for font-display
is something of a compromise between
block
and swap
. Unlike swap
, the browser blocks rendering of a font, but
swap in fallback text only for a very short period of time. Unlike block
,
however, the blocking period is extremely short.
Using the fallback
value can work well on fast networks where, if the web font
downloads quickly, the web font is the typeface used immediately on the page's
initial rendering. However, if networks are slow, the fallback text is seen
first after the blocking period elapses, and then swapped out when the web font
arrives.
optional
optional
is the most stringent font-display
value, and only uses the web
font resource if it downloads within 100 milliseconds. If a web font takes
longer than that to load, it isn't used on the page, and the browser uses the
fallback typeface for the current navigation while the web font is downloaded in
the background and placed in the browser cache.
As a result, subsequent page navigations can use the web font immediately, since
it's already downloaded. font-display: optional
avoids the layout shift seen
with swap
, but some users don't see the web font if it arrives too late on the
initial page navigation.
Font demos
Test your knowledge
When does the browser download a web font resource (assuming it isn't
fetched with a preload
directive)?
What is the only (and most efficient) format necessary to serve web fonts to all modern browsers?
Up next: Code-split JavaScript
With an understanding of font optimization under your belt, you can now move onto the next module, which covers a topic that has a high potential to improve initial page load speed for your users, and that is to defer the loading of JavaScript through code splitting. By doing so, you can keep bandwidth and CPU contention as low as possible during the startup phase of a page, a period of time in which users are quite likely to interact with it.