시작하며
Pretendard 폰트를 사용해 만든 프로젝트가 다른 유저 환경에서는 이렇게 세리프체로 출력되는 현상을 확인했다. 찾아보니 Next.js 13버전부터 폰트 최적화를 지원한다고 하여, 공식 문서를 읽어 보고 적용해 보았다.
공식문서에 이렇게 폰트 최적화에 대한 설명이 되어있다.
next/font
에는 모든 글꼴 파일에 대한 자동 자체 호스팅이 내장되어 있습니다. 이는 기본 CSS의size-adjust
속성을 사용하기 때문에 레이아웃 변경 없이 웹 글꼴을 최적으로 로드할 수 있음을 의미합니다.성능과 개인정보 보호를 염두에 두고 모든 Google 글꼴을 편리하게 사용할 수 있습니다. CSS 및 폰트 파일은 빌드 시 다운로드되며 정적 파일과 함께 자체 호스팅되어, 브라우저는 요청을 Google로 전송하지 않습니다.
ㅤ
기본 적용
// app/layout.tsx
import { Inter } from "@next/font/google";
const inter = Inter({
subsets: ["latin"],
});
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="ko" className={inter.className}>
<body>{children}</body>
</html>
);
}
Google Fonts의 Inter
폰트를 사용하려고 한다.
사용할 폰트를 next/font/google
로 부터 가져와서 변수로 설정해주고 className
으로 설정해주면 해당 폰트를 전역의 기본 폰트로 사용하게 된다.
만약 가변 글꼴(Variable Fonts)을 사용할 수 없는 경우에는 weight
를 지정해야 한다.
const inter = Inter({
weight: '400',
subsets: ['latin'],
})
ㅤ
여러 폰트 사용
첫번째 방법: className으로 적용
// app/fonts.ts
import { Inter, Roboto_Mono } from 'next/font/google';
export const inter = Inter({
subsets: ['latin'],
})
export const roboto_mono = Roboto_Mono({
subsets: ['latin'],
})
// app/layout.tsx
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="ko" className={inter.className}>
<body>{children}</body>
</html>
);
}
// app/page.tsx
import { roboto_mono } from './fonts';
export default function Page() {
return (
<>
<h1 className={roboto_mono.className}>My Page</h1>
</>
)
}
첫 번째 방법은 필요한 경우 해당 className
을 적용하는 것이다. 이렇게 하면 글꼴이 렌더링 될 때만 미리 로드된다. 위의 예시에서 Inter
는 전역적으로 적용되고 Roboto Mono
는 필요에 따라 가져오고 적용할 수 있다.
두번째 방법: CSS 변수 사용
// app/layout.tsx
import { Inter, Roboto_Mono } from 'next/font/google';
import styles from './global.css';
const inter = Inter({
subsets: ['latin'],
variable: '--font-inter',
display: 'swap',
});
const roboto_mono = Roboto_Mono({
subsets: ['latin'],
variable: '--font-roboto-mono',
display: 'swap',
});
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en" className={`${inter.variable} ${roboto_mono.variable}`}>
<body>{children}</body>
</html>
);
}
// app/global.css
html {
font-family: var(--font-inter);
}
h1 {
font-family: var(--font-roboto-meno);
}
두 번째 방법은 CSS 변수를 만들고 원하는 CSS 솔루션과 함께 사용하는 것이다. 이렇게 하면 Inter
는 전체적으로 적용되고 모든 h1
태그는 Roboto Mono
로 스타일이 지정된다.
각각의 새 폰트는 클라이언트가 다운로드해야 하는 추가 리소스이므로 여러 폰트를 사용할 때는 보수적으로 사용하는 것이 좋다.
ㅤ
Tailwind CSS를 사용하면
// app/layout.tsx
import { Inter } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
variable: '--font-inter',
});
export default function MyApp({ Component, pageProps }) {
return (
<main className={`${inter.variable}`}>
<Component {...pageProps} />
</main>
);
}
variable
를 지정해주고 Tailwind CSS 구성에 CSS 변수를 추가한다.
/** @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)'],
},
},
},
plugins: [],
}
이렇게 하면 font-sans
유틸리티 클래스를 사용해서 요소에 폰트를 적용할 수 있다.
ㅤ
Local fonts
import localFont from 'next/font/local'
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>
)
}
사용자가 지정한 local font
를 사용할 수도 있는데 next/font/local
를 가져오고 로컬 폰트 파일의 위치를 src
로 지정하면 된다.
이때 공식문서에서는 성능과 유연성 위해 가변 폰트를 사용할 것을 권장한다.
ㅤ
참고
ㅤ