웹 폰트 로딩 중 발생하는 FOIT(Flash of Invisible Text)와 FOUT(Flash of Unstyled Text) 문제를 font-display 속성, 폴백 폰트 메트릭 조정, 리소스 힌트로 해결하는 방법을 다룬다. Next.js의 next/font 모듈을 통한 자동 최적화도 포함한다.
핵심 포인트- font-display 속성 5가지 옵션(block, swap, fallback, optional, auto)으로 폰트 로딩 중 텍스트 표시 전략을 제어한다.
- CSS font-face 디스크립터(size-adjust, ascent-override, descent-override)로 폴백 폰트와 웹 폰트의 크기 불일치를 줄여 CLS를 최소화한다.
- preconnect와 preload 리소스 힌트로 폰트 다운로드를 일찍 시작해 렌더 블로킹을 줄인다.
- next/font는 빌드 타임에 폰트를 다운로드해 로컬 서빙하고, 폴백 자동 생성 및 서브셋 자동 프리로딩을 처리한다.
상세 정리- FOIT/FOUT 문제: 브라우저가 폰트 서버에서 웹 폰트를 가져오는 동안 텍스트가 보이지 않거나(FOIT) 폴백 폰트로 잠시 표시되다가 교체되는(FOUT) 현상이다. 레이아웃 이동(CLS)을 유발한다.
- font-display: block: 짧은 시간 텍스트를 숨기고 폰트 로드 완료 시 표시한다. 시각적 일관성을 우선시한다.
- font-display: swap: 폴백 폰트를 즉시 표시하고 웹 폰트 로드 후 교체한다. 콘텐츠가 즉시 보이지만 폰트 교체 시 레이아웃 이동이 발생할 수 있다.
- font-display: fallback: 100ms 짧은 블록 후 폴백을 표시하고, 3초 내에 로드되지 않으면 폴백을 영구 사용한다. block과 swap의 중간 전략이다.
- font-display: optional: 100ms 내 캐시된 폰트가 있으면 사용하고, 없으면 브라우저와 네트워크 조건에 따라 결정한다. 성능을 최우선한다.
- size-adjust 디스크립터: 폴백 폰트의 모든 메트릭을 비율로 스케일해 웹 폰트와 크기를 맞춘다. 폰트 교체 시 레이아웃 이동을 줄이는 핵심 도구다.
- ascent/descent/line-gap override: 특정 메트릭만 덮어써 폴백 폰트를 세밀하게 조정할 수 있다.
- preconnect: 폰트 서버와의 연결을 페이지 로딩 초기에 미리 수립한다. TLS 핸드셰이크 시간을 절약해 폰트 다운로드를 앞당긴다.
- preload: 브라우저에게 렌더링 전에 폰트를 가져오도록 지시한다. FOIT 시간을 단축하는 효과가 있다.
- next/font 자동화: 빌드 시 폰트를 로컬에 다운로드해 외부 네트워크 요청을 없애고, size-adjust 기반 폴백을 자동 생성하며, 사용 서브셋만 자동 프리로딩한다.
왜 읽나- 웹 폰트로 인한 CLS와 성능 저하를 해결하고 싶은 프론트엔드 개발자에게 font-display 전략 선택부터 CSS 디스크립터 튜닝과 next/font 활용까지 체계적인 가이드를 제공한다.