How Next.js Font Works
December 18, 2024 3 min read

How Next.js Font Works

A deep dive into how Next.js Font works and how to replicate it in Astro.

Introduction

I’ve been working with Astro quite a bit lately, and the lack of something like next/font has been a persistent headache. My website was suffering from CLS (Cumulative Layout Shift) issues on the initial page load, especially before the fonts were cached.

Initial Thoughts and Failed Attempts

Initially, I thought, “Oh, maybe next/font leverages some browser API or meta tag to solve this.” I figured I could probably replicate similar logic in Astro.

However, after experimenting with various approaches like font-display: swap, fallback, optional, preloading fonts, and even serving fonts locally, I still couldn’t achieve the desired results.

The Solution: astro-font

My problems were finally solved when I discovered astro-font. It seemed that astro-font and next/font share a similar mechanism. Curiosity got the better of me, so I dove into the source code to understand how it works. Here’s a breakdown:

How astro-font (and next/font) Work

  1. Font Downloading and Caching: The package downloads fonts from Google Fonts (or uses local fonts) and caches them.

  2. Preload in Header: It adds a preload tag to the document header for the font.

  3. Font Metrics and Fallback Generation: This is the core of the solution. It utilizes font metrics (such as size-adjust, ascent-override, descent-override, and line-gap-override) and the fontkit library to create a fallback font from the original font. This fallback font is derived from a local font that closely matches the dimensions of the original font. By default, it will use Arial for sans-serif fonts and Times New Roman for serif fonts. Here’s an example:

    body {
      font-family: 'Poppins', 'fallback for Poppins',
        'another fallback for Poppins';
    }
    
    @font-face {
      font-family: 'fallback for Poppins';
      src: local('Arial');
      ascent-override: 105%;
      descent-override: 35%;
      line-gap-override: 10%;
    }
  4. Rendering with Fallback: The browser initially renders the text using the fallback font. When the original font is fully loaded, the browser swaps the fallback font with the original. Because the fallback and original fonts have very similar dimensions, CLS is significantly minimized.

Further Reading on Font Metrics and Fallback Fonts

To learn more about font metrics and the background of font fallbacks, check out this excellent article from the Chrome team.

References

Conclusion

astro-font provides an elegant solution to font loading and CLS issues in Astro, mirroring the approach used by next/font. By leveraging font metrics and carefully crafting fallback fonts, it ensures a smooth user experience with minimal layout shifts. Understanding the inner workings of these tools can empower developers to optimize web performance and deliver visually stable web pages.

Explore more articles