Next.js Blog (4): Font Setup & Optimization

Contents

Notice
This text was originally translated using AI tools.

Introduction#

As the saying goes, "a cake that looks good tastes good too,"
and I believe the impact of fonts on a blog's impression is quite significant. In this post, I will explore two ways to load fonts in a Next.js environment: Google Fonts and Local Fonts.

Font combinations to be used:

  • Code area: Fira Code
  • Body area: Pretendard

Setup Preparation#

Next.js optimizes fonts via next/font. Therefore, let's prepare a separate file so that font settings can be managed in one place.

src
└── fonts
    └── index.ts

📌 Why not put them directly in the public directory?

Of course, you could place them in the public folder and call them via path. However, using the next/font feature automatically optimizes font files at build time and pre-generates the necessary CSS. Most importantly, it prevents the Layout Shift (CLS) phenomenon that occurs during font loading, which provides a positive effect on performance.

Internal Font Setup: Google Fonts (Fira Code)#

Let's bring in Fira Code to apply to the code area. Since this font is provided by Google Fonts, you can easily load it via next/font/google without having to download files separately.

// src/fonts/index.ts
import { Fira_Code } from 'next/font/google';
 
export const firaCode = Fira_Code({
	subsets: ['latin'],
	weight: ['400', '500', '600', '700'],
	display: 'swap',
	variable: '--font-fira-code',
});

External Font Setup: Local Fonts (Pretendard)#

Pretendard, which will be used for the body text, is set up as a local font. Upon checking, I found that the Variable font file reaches about 3MB, which I think is a bit burdensome for a web environment.

Therefore, for performance, I recommend using a Subset file (woff2) that contains only the necessary characters instead of the full font. Place the subset fonts you want to use within the project path.

src
└── fonts
    ├── Pretendard-Bold.subset.woff2
    ├── Pretendard-Medium.subset.woff2
    ├── Pretendard-Regular.subset.woff2
    ├── Pretendard-SemiBold.subset.woff2
    └── index.ts

Then, define it using next/font/local as follows:

// src/fonts/index.ts
import localFont from 'next/font/local';
 
export const pretendard = localFont({
	src: [
		{
			path: './Pretendard-Regular.subset.woff2',
			weight: '400',
		},
		{
			path: './Pretendard-Medium.subset.woff2',
			weight: '500',
		},
		{
			path: './Pretendard-SemiBold.subset.woff2',
			weight: '600',
		},
		{
			path: './Pretendard-Bold.subset.woff2',
			weight: '700',
		},
	],
	display: 'swap',
	variable: '--font-pretendard',
});

Applying Fonts#

Now, let's apply the defined fonts to components. You can choose the most suitable method from the ones below depending on the situation.

1. Applying at the Component Level (className)

This is the simplest method, using the className property provided by the Next.js font object. It is useful when you want to apply a font only to a specific component or layout.

import { pretendard } from '@/fonts';
 
export default function Intro() {
  return (
    <section className={pretendard.className}>
      <h1>Introduction page with font applied</h1>
    </section>
  );
}

2. Utilizing in CSS Style Sheets (CSS Variable)

This method uses the variable value specified during the next/font setup within general CSS files or Inline Styles.

/* globals.css */
.custom-title {
	font-family: var(--font-pretendard);
	font-weight: 700;
}
 
code {
	font-family: var(--font-fira-code);
}

3. Integrating with Tailwind v4

In Tailwind v4, variables are mapped directly in the main CSS file (globals.css). First, inject the font variables into the top-level tag.

// src/pages/_app.tsx
<html lang="ko" className={`${pretendard.variable} ${firaCode.variable}`}>

Then, override the default font-family in the CSS file using the @theme block with the fonts we defined.

/* src/styles/globals.css */
@import 'tailwindcss';
 
@theme {
	/* Assign the --font-pretendard variable as Tailwind's sans font */
	--font-sans: var(--font-pretendard);
 
	/* Assign the --font-fira-code variable as Tailwind's mono font */
	--font-mono: var(--font-fira-code);
}

By setting it up this way, you can apply our optimized fonts when using the font-sans (default) and font-mono (code area) classes throughout the project without additional script configuration.

📌 Note: Difference Between Tailwind Theme Variables and General CSS Variables

Values like --font-sans defined inside Tailwind v4's @theme are for creating Tailwind's internal utility classes. Therefore, if you use var(--font-sans) directly in a general CSS file, the browser may not recognize it.


Conclusion#

While finishing the font setup, I felt that defining styles became somewhat dualized since the overall blog style is controlled by Tailwind CSS while the Markdown body is managed by general CSS.

I should look for a way to manage this more cleanly.