당신의 쇼핑몰이나 블로그가 데스크톱에서는 빠른데, Lighthouse 모바일 검사에서만 유독 느려짐이 드러난다. LCP(Largest Contentful Paint, 가장 큰 내용이 그려지는 시각)가 10초를 넘긴다. 자바스크립트 번들을 쪼개고 이미지를 줄여도 점수가 꿈쩍 않는다. 또는 랜딩 페이지 제목 한 줄을 예쁜 명조로 쓰려고 next/font/google 로 Noto Serif KR 을 넣었더니, 글자 서른 자를 그리려고 수백 KB 용량을 받고 있다. 둘 다 원인은 같은 곳에 있다 — 한글 웹폰트다.
한글 웹폰트는 왜 페이지에서 가장 무거운 파일이 되나
한글 웹폰트는 글자 수천 개를 담고 있어서, 아무 손질 없이 한 파일로 실으면 페이지의 자바스크립트 전체보다 무거운 파일이 된다. 영문 폰트는 글자 수백 개라 수십 KB 지만, 한글은 완성형 음절만 11,172자이고 상용 폰트도 2,350자 이상을 담는다. 굵기마다 한 파일씩이니 두 굵기면 두 배다. 그리고 웹폰트는 글자가 화면에 그려지는 경로 위에 있어서, 폰트가 늦으면 제목·본문이 늦고 LCP 가 늦는다.
그래서 한글 사이트의 모바일 성능 점검은 자바스크립트보다 폰트를 먼저 본다. 개발자 도구 네트워크 탭에서 font 만 걸러 전송량을 더해 보는 것이 첫 단계다.

쓰는 글자만 보내는 두 가지 방법
어느 쪽이 맞는지는 화면에 나올 글자를 미리 알 수 있는가로 정한다.
| 상황 | 방법 | 예 |
|---|---|---|
| 글이 계속 바뀐다 (블로그·상품 설명·게시판) | unicode-range 로 나눈 조각 폰트 | 쓰인 글자가 든 조각만 내려받는다 |
| 문구가 고정됐다 (제목·로고 글자·안내 몇 줄) | 쓰는 글자만 잘라 낸 서브셋 폰트 | 파일 하나, 수십 KB |
조각 폰트(dynamic subset). 폰트를 글자 구간별 여러 파일로 나누고 @font-face 마다 unicode-range 를 적으면, 브라우저가 화면에 실제 나온 글자가 든 조각만 받는다. 한글 폰트 배포처 대부분이 이 꼴의 CSS 를 따로 제공하니, 단일 파일을 부르던 한 줄을 조각 CSS 로 바꾸는 것으로 끝나는 경우가 많다.
고정 문구 서브셋. 화면 문구가 코드에 박혀 있다면 그 글자만 뽑아 폰트를 자른다. fontTools 의 pyftsubset 로 한 줄이다.
# 소스에 나오는 글자를 모아 chars.txt 로 만든 뒤
pyftsubset NotoSerifKR-Regular.ttf --text-file=chars.txt \
--flavor=woff2 --output-file=title-subset.woff2
그다음 Next.js 라면 next/font/local 로 그 파일을 싣는다. next/font/google 은 2026-10 기준 한글 폰트에 쓸 만한 subsets 값이 없어, 조각 CSS 를 통째로 붙이고 화면에 나온 글자마다 조각을 받는다.
서브셋에서 빠진 글자는 어떻게 알아채나
서브셋에 없는 글자는 오류 없이 시스템 폰트로 그려진다. 콘솔에도 아무것도 안 뜨고, 그 글자 하나만 모양이 다르다. 문구를 고친 사람이 폰트를 다시 굽지 않으면 몇 주 뒤에야 누군가 "이 글자만 이상하다"고 말한다. 그래서 굽는 일과 같이 테스트를 둔다.
// 화면 소스에 나오는 모든 글자가 서브셋 글자 목록 안에 있어야 한다
const used = collectCharsFromSource('app/**/*.tsx');
const baked = readFileSync('fonts/chars.txt', 'utf8');
const missing = [...used].filter((c) => !baked.includes(c));
expect(missing).toEqual([]); // 실패하면: 폰트 서브셋을 다시 굽는다
확인 목록:
- 네트워크 탭에서
font전송량 합계가 자바스크립트 합계보다 크지 않은가 - 고정 문구 화면이 조각 CSS 를 통째로 붙이고 있지 않은가(렌더를 막는 CSS 크기도 본다)
- 서브셋을 쓴다면 "소스 글자 ⊂ 서브셋 글자" 테스트가 CI 에 있는가
- 런타임에 조립되는 문자열(브라우저 오류 문구, 외부 API 응답, 사용자 이름)이 그 폰트로 그려지지 않는가 — 테스트가 못 잡는 자리다. 그런 자리는 조각 폰트나 시스템 폰트를 쓴다
우리가 겪은 일
- 모바일 LCP 12초의 원인이 단일 파일 한글 폰트 2MB 였다 — 자바스크립트 전체(300KB)의 7배. 조각 폰트 CSS 로 한 줄 바꾸자 전송량 2.4MB → 0.85MB, 모바일 성능 점수 60대 → 80대가 됐다.
- 제목·안내 서른 자에 조각 13개 약 564KB 를 받고 있었다.
next/font/google이 조각@font-face249개(렌더를 막는 CSS 약 155KB)를 붙인 탓이었다. 쓰는 글자만 잘라next/font/local로 싣자 약 77KB, 7배 작아졌다. 대신 빠진 글자 테스트를 같이 두었다.