Font optimization in Next.js 13

Introduction

When creating a website with performance and SEO as key features, font optimization becomes a crucial consideration. In the ever-evolving world of web development, where user experience and page load times are paramount, even the smallest details can make a significant impact. One such detail that often gets overlooked is the way we handle fonts.

Fonts play an integral role in shaping the visual identity of a website. They set the tone, convey the brand's personality, and ensure that the content is not only legible but also aesthetically pleasing. However, if not optimized properly, fonts can become a performance bottleneck, causing slow page load times and potentially harming your search engine rankings.

In this blog post, we'll delve into the world of font optimization in the context of Next.js 13, my favorite framework for building modern, server-rendered React applications. We'll explore why font optimization matters, the challenges it presents, and practical techniques and tools to streamline font delivery, minimize performance impact, and enhance your website's SEO.

Why Font Optimization Matters

Before we dive into the specifics of font optimization in Next.js 13, let's understand why it matters in the first place.

  1. Page Load Speed: Research shows that users expect websites to load in a matter of seconds. Slow-loading websites leads to higher bounce rates, lower user engagement, and decreased conversions. Unoptimized fonts can significantly contribute to page load times, as they are additional resources that need to be fetched and rendered.

  2. Mobile Responsiveness: With the increasing use of mobile devices for browsing, optimizing fonts becomes even more critical. Mobile networks can be slower than broadband connections and mobile devices have limited processing power. Optimized fonts ensure a smoother experience for mobile users.

  3. SEO Rankings: Search engines like Google consider page speed as a ranking factor. Faster websites tend to rank higher in search results. Therefore, optimizing fonts can indirectly impact your SEO rankings and organic traffic.

  4. User Experience: Fonts affect the overall look and feel of your website. If fonts are not optimized and cause layout shifts or visual glitches during loading, it can create a poor user experience, leading to user frustration.

To handle font optimization, Next.js introduces next/font which assists in making sure fonts are loaded efficiently on your website.

What is next/font?

Next/font gives you the ability to optimally and painlessly load fonts within your Next.js website.

[From Docs] next/font system also allows you to conveniently use all Google Fonts with performance and privacy in mind. CSS and font files are downloaded at build time and self-hosted with the rest of your static assets. No requests are sent to Google by the browser.

There are a few requirements needed for you to be able to use next/font:

  1. You must be using Next 13 (or newer)

  2. You must be using a Google font or a local font.

If you’re not using Next 13, or need a different font library then Fontsource is a great alternative, but it requires a little more configuration.

How to optimise fonts with next/font

Next/font is already included in Next.js directly and we don't need to install any package to use it.

Like I mentioned above, next/font provides two way of importing fonts, either google fonts or local fonts. Regardless of whether we are using google or local font's, we can use fonts in two ways:

  • Import them globally (recommended)

  • Import them on individual pages

Using Google Fonts

This allows us to automatically self-host any Google Font within our deployment. With this feature, the fonts become an intrinsic part of the deployment package and are seamlessly served from the same domain as your website. Consequently, there is no necessity for the browser to dispatch requests to Google's servers. This not only streamlines font delivery but also enhances both the performance and privacy of your web application.

Get started by importing the font you would like to use from next/font/google as a function.

//app/layout.tsx
import { Inter } from 'next/font/google'

// If loading a variable font, you don't need to specify the font weight
const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
})

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en" className={inter.className}>
      <body>{children}</body>
    </html>
  )
}

To learn more about using Google fonts, check here

Using Local fonts

Import next/font/local and specify the src of your local font file. Like Google Fonts, it’s recommended to use variable fonts if possible.

//app/layout.tsx
import localFont from 'next/font/local'

// Font files can be colocated inside of `app`
const myFont = localFont({
  src: './my-font.woff2',
  display: 'swap',
})

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en" className={myFont.className}>
      <body>{children}</body>
    </html>
  )
}

If you can’t use a variable font, you’ll likely need to import a handful of font files which you can do by including them as an array.

const roboto = localFont({
  src: [
    {
      path: './Roboto-Regular.woff2',
      weight: '400',
      style: 'normal',
    },
    {
      path: './Roboto-Italic.woff2',
      weight: '400',
      style: 'italic',
    },
    {
      path: './Roboto-Bold.woff2',
      weight: '700',
      style: 'normal',
    },
    {
      path: './Roboto-BoldItalic.woff2',
      weight: '700',
      style: 'italic',
    },
  ],
})

You can check out here for more details about using local fonts.

With Tailwind CSS

Like any other tool, we would like to make it easier to work with our favorite styling library. next/font can be used with Tailwind CSS through a CSS variable.

In the example below, we use the font Inter from next/font/google (you can use any font from Google or Local Fonts). Load your font with the variable option to define your CSS variable name and assign it to inter. Then, use inter.variable to add the CSS variable to your HTML document.

//app/layout.tsx
import { Inter, Roboto_Mono } from 'next/font/google'

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-inter',
})

const roboto_mono = Roboto_Mono({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-roboto-mono',
})

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en" className={`${inter.variable} ${roboto_mono.variable}`}>
      <body>{children}</body>
    </html>
  )
}

Finally, add the CSS variable to your Tailwind CSS config:

// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{js,ts,jsx,tsx}',
    './components/**/*.{js,ts,jsx,tsx}',
    './app/**/*.{js,ts,jsx,tsx}',
  ],
  theme: {
    extend: {
      fontFamily: {
        sans: ['var(--font-inter)'],
        mono: ['var(--font-roboto-mono)'],
      },
    },
  },
  plugins: [],
}

You can now use the font-sans and font-mono utility classes to apply the font to your elements.

Conclusion

It’s as easy as that. Now you’ve got next/font set up you can be certain that you’re loading fonts most optimally across your entire project with minimal effort.

peace out goodbye GIF by Red Bull

Keep coding :)

🤖