Avoid layout shifts caused by web fonts

Determine the @font-face block from all current stylesheets on the page, find the display property, and check if it’s set to an optional value.

Description

The Cumulative Layout Shift (CLS) is a metric that quantifies how often users experience sudden shifts in page content. When a web font is downloaded, the size of the contained element changes, which causes layout shifts. This happens when the system font and the web font have different font heights or paragraph lengths. To prevent layout shifts, we recommend using font-display: optional;.

This directive, which is located in your @font-face declaration, instructs the browser to fall back to the system font in case the web font is not accessible at the time that text is rendered (plus 100 ms). This indicates that subsequent page loads should render using the web font, as it will have been downloaded and made accessible in cache, but uncached page loads may still use the fallback font. There are other choices, as seen in the illustration below:

Font display loading flow
  • block – gives the font face a short block period (3s is recommended in most cases) and an infinite swap period.
  • swap – gives the font face an extremely small block period (100ms or less is recommended in most cases) and an infinite swap period.
  • fallback – gives the font face an extremely small block period (100ms or less is recommended in most cases) and a short swap period (3s is recommended in most cases).
  • optional – if the font can be loaded immediately (such that it’s available to be used for the first paint of the text), the font is used. Otherwise, the font is treated as if its block period and swap period both expired before it finished loading. If the font is not used due to this, the user agent may choose to abort the font download or download it with a very low priority. If the user agent believes it would be useful for the user, it may avoid even starting the font download and proceed immediately to using a fallback font.

How to fix it

  • When using Google Fonts, ensure option display is set to optional.

    Bad example for Google Fonts
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Russo+One&display=swap" rel="stylesheet">
    
    Good example for Google Fonts
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Russo+One&display=optional" rel="stylesheet">
    

    Then in your CSS, you do not need to use the @font-face, you simply add the font-family to your class/tag, like so:

    body {
      font-family: 'Inter';
      font-size: 1rem;
    }
    
  • When using @font-face in CSS simply add font-display: optional; to your @font-face block.

    Example of @font-face section with font-display: optional;
    @font-face {
      font-family: 'Inter';
      font-style: normal;
      font-weight: 300;
      font-display: optional;
      src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7W0Q5n-wU.woff2) format('woff2');
      unicode-range: U+1F00-1FFF;
    }
    

Standard

Rule ID: layout-shifts-with-font-display

Best Practice, Performance, SiteLint