Async Font CSS with Font-Display Block Behavior

A demo by Scott Jehl

The heading above is styled using a third-party Google font, using their link-based embed. The stylesheet has some additional attributes to cause it to load asynchronously, preventing it from blocking all page rendering while it's loading, and to load it at a high priority as well.

Loading the CSS asynchonously will cause the heading to display in a fallback font until the CSS loads and defines the custom font using its @font-face rules. This flash of unstyled type is undesirable, so in order to hide the heading while the custom font's CSS file is loading, some CSS is used to set the heading's text color to transparent for a maximum of 3s, using CSS @keyframes. If the CSS happens to load sooner than that, its onload handler will set its media type from "print" to "all," causing the CSS to unapply immediately. If the CSS fails to load quickly, or at all, the text will appear after 3 seconds using a fallback font until the custom font becomes available. This means users will see a typical font-display: block; behavior, where the custom font is given 3 seconds to style the text before the text is revealed using a fallback font.

Source:

<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Buda:wght@300&display=block" rel="stylesheet" media="print" onload="this.media='all'" fetchpriority="high">
<style>
  /* async-css-friendly font-display: block behavior. 3s max hiding tolerance */
  @keyframes briefblock {
    0%,99% { color: transparent; }
  }
  html:has(link[href*="googleapis"][media="print"]) h1 {
    animation: briefblock 3s;
  }
  h1 {
    font-family: "Buda", serif;
  }
</style>