Google Fonts debugging for Cumulative Layout Shift (CLS)

When we use Google Fonts, it will cause the Cumulative Layout Shift (CLS) problem. Here is the whole workflow about using the Google Fonts

  1. Use the default font to render the page
  2. Download the Google Fonts
  3. Loading the Google Fonts successfully and swapping the page’s font.

Step 3 is the step that causes the Cumulative Layout Shift (CLS) problem. It will re-render the page and the DOM element on the screen will become bigger or smaller. Then it will move the element.

Solve Google Fonts Cumulative Layout Shift (CLS) problem

Place the link at the top will tell the browser to start the web font loading process as early as possible.

<!-- 1: links at top of head -->
<head>
  <meta charset="utf-8">
  <link href="https://fonts.googleapis.com/css2?family=Roboto" rel="stylesheet">
</head>

2. Preconnect to Google Fonts

When we use Google Fonts, it will connect to https://fonts.googleapis.com first. And download the fonts from https://fonts.gstatic.com/

/* cyrillic */
@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 400;
  src: url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu5mxKKTU1Kvnz.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

Google Fonts debugging for Cumulative Layout Shift (CLS)

<!-- 2: preconnect -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

3. Use font-display

font-display options CLS Description
optional Best Hide the text for up to 100ms, then only use the web font if it is available - never swapping. Many users will not see the web font at all, since it will only be shown after it is downloaded.
fallback Middle Hide the text for up to 100ms, then only swap in the web font if it loads within 3 seconds. There is some layout shift, and a worse CLS score. If the font was loading to long (more than 3 seconds), then it will use default font (optional)
swap Worse (FOUT) Show the content asap. When the fonts are loaded then swap the fonts (CLS). Most users will see the font, but they will experience layout shift if the font arrives late.
block Worse (FOIT) Hide the content for up to 3 seconds then show the content, when the fonts are loaded then swap the fonts (CLS).
auto Worse (FOIT) Default from browser (block)

Google Fonts debugging for Cumulative Layout Shift (CLS)

<head>
  <!-- 3: use font-display -->
  <link href="https://fonts.googleapis.com/css2?family=Roboto&display=optional" rel="stylesheet">
</head>

4. Final scripts

<!-- 1: links at top of head -->
<head>
  <meta charset="utf-8">
  <!-- 2: preconnect -->
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <!-- 3: use font-display -->
  <link href="https://fonts.googleapis.com/css2?family=Roboto&display=optional" rel="stylesheet">
</head>

What is FOUT and FOIT

A. FOUT (Flash of Unstyled Text)

Old browser default behavior

Loading the fonts was too slow. And the browser use the default fonts instead. But when fonts load finish and the pages will flash

B. FOIT(Flash of Invisible Text)

New browser default behavior

Loading the fonts was too slow. The fonts can not show up. But when fonts load finish and the pages will flash

Reference