폰트 최적화
웹 페이지에서 폰트(Font)는 이미지 다음으로 용량이 큰 자원입니다. 그래서 폰트 로딩 방식은 페이지 성능에 직접적인 영향을 줍니다.
폰트 파일이 크거나 로딩이 비효율적이면 텍스트 표시 지연, FOIT(Flash Of Invisible Text), FOUT(Flash Of Unstyled Text) 같은 문제가 발생해 사용자 경험을 해칠 수 있습니다.
Next.js는 이런 문제를 줄이기 위한 폰트 최적화 기능을 내장하고 있습니다.
이 절에서는 폰트 최적화의 중요성, Next.js의 next/font 컴포넌트 사용법, 그리고 폰트 로딩 성능을 개선하기 위한 다양한 전략들을 알아보겠습니다.
폰트 최적화의 중요성
- 성능 저하: 웹 폰트 파일은 용량이 크기 때문에 다운로드 시간이 길어지면 페이지 렌더링을 지연시킬 수 있습니다. 이는 특히 모바일 환경이나 네트워크 속도가 느린 환경에서 더욱 두드러집니다.
- CLS(Cumulative Layout Shift) 발생: 폰트 파일 로딩이 완료되기 전에 대체 폰트(fallback font)로 텍스트가 렌더링되다가 폰트가 로드된 후 레이아웃이 변경될 때 CLS가 발생합니다. 이는 사용자의 시각적 안정성을 해치고 Core Web Vitals 점수에 부정적인 영향을 미칩니다.
-
FOIT/FOUT 현상
- FOIT (Flash Of Invisible Text): 폰트가 로딩될 때까지 텍스트가 전혀 보이지 않는 현상입니다. 사용자에게 빈 화면을 보여주어 답답함을 유발합니다.
- FOUT (Flash Of Unstyled Text): 폰트가 로딩될 때까지 시스템 기본 폰트나 대체 폰트로 텍스트가 표시되다가, 로딩이 완료되면 웹 폰트로 교체되면서 글꼴이 갑자기 바뀌는 현상입니다.
폰트 최적화는 이러한 문제들을 해결하여 웹 페이지의 시각적 안정성과 로딩 성능을 향상시키는 데 기여합니다.
next/font 컴포넌트 사용하기
Next.js 13부터 도입된 next/font는 Google Fonts 및 로컬 폰트를 자동으로 최적화해 주는 강력한 기능입니다. 이 모듈은 폰트 파일 다운로드를 최적화하고, font-display 속성을 자동으로 설정하여 FOIT/FOUT 문제를 최소화하며, 폰트 메트릭스를 자동으로 조정하여 CLS를 방지합니다.
next/font는 서버에서 폰트를 처리하고 빌드 시점에 폰트 파일을 정적으로 처리하여 가장 빠른 폰트 로딩을 보장합니다.
Google Fonts 최적화
Google Fonts는 웹에서 가장 널리 사용되는 폰트 서비스 중 하나입니다. next/font/google을 사용하면 Google Fonts를 빠르고 효율적으로 불러올 수 있습니다.
폰트 불러오기:
src/app/layout.tsx (루트 레이아웃) 또는 개별 페이지/컴포넌트 파일에서 next/font/google을 임포트하고 사용할 폰트를 설정합니다.
import './globals.css';
import { Inter, Noto_Sans_KR } from 'next/font/google'; // 사용할 폰트 임포트
// 1. Inter 폰트 설정 (영문 기본 폰트)
const inter = Inter({
subsets: ['latin'], // 필요한 서브셋 지정 (용량 최적화)
display: 'swap', // FOIT/FOUT 방지를 위한 display 속성 (자동 설정되지만 명시적 지정)
variable: '--font-inter', // CSS 변수로 사용하기 위한 이름 지정
});
// 2. Noto Sans KR 폰트 설정 (한글 폰트)
// weight: 사용할 폰트 두께 지정 (용량 최적화)
// display: 'swap' (FOUT 방식)
// variable: CSS 변수 이름 지정
const notoSansKr = Noto_Sans_KR({
subsets: ['latin'], // 한글 폰트이지만 'latin' 서브셋도 필요할 수 있음
weight: ['100', '400', '700', '900'], // 사용할 두께만 지정하여 용량 최적화
display: 'swap',
variable: '--font-noto-sans-kr',
});
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
// 3. body 태그에 CSS 변수 클래스 적용
// classNames 라이브러리 등을 사용하여 조건부 클래스 적용 가능
<html lang="ko" className={`${inter.variable} ${notoSansKr.variable}`}>
<body>{children}</body>
</html>
);
}CSS에서 폰트 사용:
src/app/globals.css 파일에서 위에서 설정한 CSS 변수를 사용하여 폰트를 적용합니다.
html, body {
padding: 0;
margin: 0;
font-family: var(--font-noto-sans-kr), var(--font-inter), sans-serif;
/* 한글 폰트를 먼저 지정하여 우선 순위를 줍니다. */
}
h1, h2, h3, h4, h5, h6 {
font-family: var(--font-noto-sans-kr), var(--font-inter), sans-serif;
}
/* 특정 요소에 Inter 폰트 적용 예시 */
.english-only {
font-family: var(--font-inter), sans-serif;
}
/* 폰트 두께 사용 예시 */
.font-thin {
font-weight: var(--font-noto-sans-kr), 100;
}
.font-bold {
font-weight: var(--font-noto-sans-kr), 700;
}next/font/google의 주요 옵션
subsets: 사용할 폰트 서브셋을 지정합니다 (예:['latin'],['korean']). 필요한 서브셋만 로드하여 파일 크기를 줄이는 데 매우 중요합니다. 한글 폰트의 경우['korean']을 사용할 수 있지만, 일부 글리프가 누락될 수 있으므로['latin', 'korean']을 함께 사용하는 경우도 있습니다.weight: 사용할 폰트 두께를 지정합니다 (예:['400', '700']). 모든 두께를 로드할 필요 없이 필요한 두께만 로드하여 용량을 최적화합니다.display: 폰트 로딩 전략을 설정합니다.swap(권장): 폰트가 로드될 때까지 대체 폰트로 텍스트를 먼저 표시한 후, 폰트가 로드되면 교체합니다. (FOUT 방지, CLS 발생 가능)optional:swap과 유사하지만, 네트워크 상황이 좋지 않으면 웹 폰트 대신 시스템 폰트를 계속 사용합니다.fallback: 폰트가 로드될 때까지 텍스트를 숨기다가 로딩되면 표시합니다. (FOIT 발생)auto: 브라우저 기본 동작에 따릅니다.
variable: 폰트의 CSS 변수 이름을 지정합니다. 이를 통해 CSS 파일에서var(--font-변수명)형태로 폰트를 쉽게 적용할 수 있습니다.preload: (불리언) 폰트를 미리 로드할지 여부를 결정합니다. 기본적으로true입니다. LCP(Largest Contentful Paint) 개선에 도움이 됩니다.
로컬 폰트 최적화
직접 호스팅하는 폰트 파일도 next/font/local을 사용하여 최적화할 수 있습니다.
폰트 파일 준비:
프로젝트 내에 폰트 파일을 저장할 디렉토리를 생성합니다 (예: src/fonts). 여기에 my-custom-font.woff2 와 같은 폰트 파일을 넣습니다. WOFF2 형식은 가장 최신이고 압축 효율이 좋은 형식으로 권장됩니다.
폰트 불러오기:
next/font/local을 사용하여 폰트 파일을 불러옵니다.
import './globals.css';
import localFont from 'next/font/local'; // 로컬 폰트 임포트
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'], variable: '--font-inter', display: 'swap' });
// 1. 로컬 폰트 설정
const myCustomFont = localFont({
src: [
// 여러 폰트 두께 및 스타일을 지정할 수 있습니다.
{
path: '../fonts/my-custom-font-thin.woff2',
weight: '100',
style: 'normal',
},
{
path: '../fonts/my-custom-font-regular.woff2',
weight: '400',
style: 'normal',
},
{
path: '../fonts/my-custom-font-bold.woff2',
weight: '700',
style: 'normal',
},
],
display: 'swap',
variable: '--font-my-custom',
});
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
// 2. body 태그에 CSS 변수 클래스 적용
<html lang="ko" className={`${inter.variable} ${myCustomFont.variable}`}>
<body>{children}</body>
</html>
);
}html, body {
padding: 0;
margin: 0;
font-family: var(--font-my-custom), var(--font-inter), sans-serif;
}next/font/local의 주요 옵션
src: 폰트 파일의 경로 배열. 각 객체는path,weight,style을 포함할 수 있습니다.display,preload,variable등은 Google Fonts와 동일하게 작동합니다.
폰트 최적화를 위한 추가 전략
next/font를 사용하는 것 외에도 폰트 로딩 성능을 더욱 개선할 수 있는 몇 가지 전략이 있습니다.
- 필요한 폰트만 로드: 모든 폰트 두께(thin, regular, bold, black 등)와 모든 스타일(normal, italic)을 한꺼번에 로드하면 폰트 파일 용량이 크게 늘어납니다. 실제로 사용되는 두께와 스타일만 선택하여 로드하세요. (Google Fonts의
weight및subsets옵션 활용) -
폰트 형식 선택
- WOFF2: 현재 가장 효율적인 웹 폰트 형식입니다. 대부분의 최신 브라우저에서 지원하며, WOFF보다 약 30% 더 압축됩니다.
- WOFF: WOFF2를 지원하지 않는 구형 브라우저를 위한 대체 형식으로 사용할 수 있습니다.
- TrueType (TTF), OpenType (OTF): 웹에서는 거의 사용되지 않으며, 파일 크기가 매우 크므로 피해야 합니다.
font-display속성 이해 및 활용: CSS@font-face규칙에서font-display속성을 사용하여 폰트 로딩 방식을 제어할 수 있습니다.next/font는 이 속성을 자동으로 최적화해 주지만, 수동으로 폰트를 로드할 경우 중요합니다.swap(권장): 폰트가 로드될 때까지 대체 폰트를 먼저 표시한 후, 웹 폰트로 교체합니다. 사용자에게 빠르게 텍스트를 보여줄 수 있어 FOIT를 방지합니다.block: 폰트가 로드될 때까지 텍스트를 숨깁니다 (FOIT). 짧은 기간만 숨기고 이후 대체 폰트를 보여줄 수 있습니다.fallback:block과swap의 중간. 텍스트를 짧게 숨긴 후 대체 폰트를 표시하고, 웹 폰트 로딩이 완료되면 교체합니다.optional:fallback과 유사하지만, 네트워크 상황에 따라 웹 폰트 로드를 포기하고 대체 폰트를 계속 사용할 수 있습니다.
font-loadingAPI (고급): JavaScript의Font Loading API를 사용하여 폰트 로딩 상태를 직접 제어하고, 폰트 로드 완료 후 특정 동작을 수행할 수 있습니다. 이는 더 세밀한 제어가 필요할 때 사용됩니다.- 폰트 서브셋팅 (Subsetting): 사용하지 않는 언어 글리프나 문자를 제거하여 폰트 파일 크기를 줄이는 기술입니다. 한글 폰트의 경우 모든 문자를 포함하면 용량이 매우 커지므로, 특정 목적(예: 웹사이트 제목)으로만 사용되는 폰트라면 서브셋팅을 고려할 수 있습니다. (폰트 제공업체 또는 도구를 통해 가능)
- CDN 활용: 폰트 파일을 CDN(Content Delivery Network)에 호스팅하면 사용자에게 지리적으로 가까운 서버에서 폰트를 제공하여 로딩 속도를 향상시킬 수 있습니다.
폰트 최적화는 웹 성능 최적화의 중요한 부분이며, next/font와 같은 Next.js의 내장 도구를 활용하면 개발자가 직접 복잡한 설정을 할 필요 없이 빠르고 안정적인 폰트 로딩을 구현할 수 있습니다.