한글 웹폰트 최적화: 서브셋부터 font-display까지 순서대로

사이트를 열면 글자가 한 박자 늦게 뜨거나, 처음엔 다른 글꼴로 보이다가 원래 폰트로 바뀐다. 혹은 첫 화면이 뜨는 데까지 유독 오래 걸린다. 원인을 따라가 보면 폰트 파일에 닿는 경우가 많다. 한글 웹폰트는 라틴 폰트보다 파일이 수십 배 무거워서, 아무 전략 없이 불러오면 그대로 로딩 속도에 얹힌다. 그렇다고 디자인을 포기하고 시스템 폰트로 돌아갈 필요는 없다. 무게를 줄이는 데는 정해진 순서가 있고, 순서대로 밟으면 글꼴은 그대로 두면서 파일만 가벼워진다.

왜 한글 폰트만 유독 무거운가

라틴 알파벳으로 웹사이트에 필요한 글자를 대략 채우려면 대문자·소문자·숫자·기호를 합쳐 수백 자면 된다. 한글은 사정이 다르다. 자음과 모음을 조합해 만드는 완성형 글자만 유니코드 기준 11,172자에 이른다. 폰트는 이 글자 하나하나의 모양(글리프)을 전부 담아야 하니, 같은 굵기 한 벌이라도 파일이 훨씬 커진다.

여기에 굵기(Regular, Bold 등)를 여러 개 쓰면 그만큼 배로 늘어난다. 한글 웹폰트 한 세트가 이미지 여러 장만큼의 용량을 차지하는 것은 이런 구조 때문이다.

그래서 한글 웹 최적화는 '어떤 폰트가 가볍냐'를 고르는 문제가 아니라, '무거운 폰트를 어떻게 나눠서 필요한 만큼만 내려받게 하느냐'의 문제다. Pretendard든 Noto Sans KR이든 원본은 무겁고, 승부는 불러오는 방식에서 갈린다.

1단계 — 서브셋: 안 쓰는 글자를 버린다

가장 먼저 할 일은 서브셋(subset)이다. 폰트에 담긴 11,000여 자 가운데 실제로 쓰지 않는 글자를 덜어내 파일을 만드는 작업이다. 회사 소개 페이지에 한자나 특수 문자가 거의 없다면, 그 글자들을 폰트에 담고 있을 이유가 없다.

서브셋에는 두 가지 방식이 있고, 성격이 다르다.

선택 기준은 '내용이 고정돼 있느냐'다. 문구가 거의 바뀌지 않는 소개형 사이트라면 정적 서브셋이 가장 효율적이다. 반대로 게시판·후기처럼 방문자가 어떤 글자를 입력할지 미리 알 수 없는 영역이 있다면, 그 부분에는 정적 서브셋을 함부로 쓰면 안 된다. 담지 않은 글자가 깨져 보일 수 있기 때문이다. 이럴 때는 동적 서브셋이나 전체 폰트를 쓰되 다음 단계들로 무게를 줄인다.

  • 정적(static) 서브셋: 미리 정한 글자 집합만 담아 하나의 파일로 고정한다. 가장 가볍지만, 담지 않은 글자가 화면에 나오면 그 글자만 다른 글꼴로 대체돼 보인다.
  • 동적(dynamic) 서브셋: 페이지에 실제로 등장하는 글자를 기준으로 필요한 조각만 내려받는다. Pretendard는 공식적으로 이 동적 서브셋 방식을 제공해, 직접 도구를 다루지 않아도 적용하기 쉽다.

2단계 — unicode-range: 폰트를 조각으로 나눠 필요할 때만 내려받는다

서브셋이 '전체에서 안 쓰는 글자를 버리는' 작업이라면, unicode-range는 '남은 글자를 여러 조각으로 나눠, 그 조각이 실제로 쓰일 때만 내려받게 하는' 방법이다. @font-face 규칙에 unicode-range를 지정하면, 브라우저는 그 범위의 글자가 페이지에 등장할 때만 해당 폰트 파일을 요청한다.

예를 들어 한글을 자주 쓰는 구간과 드물게 쓰는 구간, 라틴·숫자 구간을 서로 다른 조각으로 나눠 두면, 라틴 글자만 있는 페이지에서는 무거운 한글 조각을 아예 내려받지 않는다. 실제로 Google Fonts가 Noto Sans KR 같은 한글 폰트를 제공할 때 이 방식으로 잘게 쪼개, 페이지에 필요한 조각만 전송한다.

직접 설정할 때의 요령은, 실제 방문자에게 자주 보이는 글자를 담은 조각을 먼저 가볍게 만들어 두는 것이다. 첫 화면에 필요한 조각이 작을수록 글자가 빨리 뜬다. unicode-range는 서브셋과 충돌하지 않는다. 서브셋으로 큰 덩어리를 덜어낸 뒤, 남은 것을 range로 다시 나누는 순서로 함께 쓴다.

3단계 — woff2: 같은 글자를 더 작은 파일로

여기까지 왔으면 '담을 글자'는 정리됐다. 다음은 같은 글자를 더 작은 파일로 만드는 단계, 즉 폰트 형식이다. 결론부터 말하면 웹에서는 woff2를 쓴다.

woff2는 웹폰트 전용 압축 형식으로, 예전의 ttf·otf나 woff보다 같은 글꼴을 더 작게 압축한다. 오늘날 쓰이는 브라우저 대부분이 지원하므로, 한글 폰트처럼 원본이 무거울수록 형식만 바꿔도 전송 용량이 눈에 띄게 줄어든다.

@font-face에서 여러 형식을 함께 적되, woff2를 먼저 두어 지원하는 브라우저가 이를 우선 내려받게 한다.

폰트 제공처에서 이미 woff2를 배포한다면 변환할 필요 없이 그대로 쓰면 된다. ttf만 있다면 변환 도구로 woff2를 만들어 올린다. 이 단계는 글자 모양을 전혀 바꾸지 않으면서 파일만 줄이므로, 디자인 손실 걱정 없이 적용할 수 있다.

  • src에 format('woff2')로 지정한 woff2를 맨 앞에 둔다.
  • 아주 오래된 브라우저까지 받쳐야 한다면 그 뒤에 woff 등을 대비책으로 둔다. 그렇지 않다면 woff2 하나로도 충분한 경우가 많다.

4단계 — font-display: 글자가 뜨는 타이밍을 통제한다

앞의 세 단계가 '무엇을 얼마나 내려받나'를 줄였다면, font-display는 '내려받는 동안 화면을 어떻게 보여줄까'를 정한다. 폰트가 아직 도착하지 않았을 때 브라우저가 취하는 행동을 지정하는 속성이다.

아무것도 지정하지 않으면 브라우저는 폰트를 기다리는 동안 글자를 잠깐 감추는 쪽(FOIT)으로 동작하기 쉽다. 방문자 눈에는 '내용은 떴는데 글자가 안 보이는' 순간이 생긴다. font-display로 이 행동을 바꾼다.

브랜드 글꼴을 확실히 보여주는 것이 중요하면 swap이, 로딩 안정성과 속도가 우선이면 optional이 무난하다. 교체 순간의 어긋남(레이아웃 이동)이 걱정되면, 대체 글꼴의 크기와 자간을 웹폰트와 비슷하게 맞춰 흔들림을 줄일 수 있다. 정답이 하나는 아니며, 사이트 성격에 맞춰 고르는 항목이다.

  • swap: 폰트가 오기 전에는 대체 글꼴로 글자를 바로 보여주고, 폰트가 도착하면 교체한다. 글자가 안 보이는 구간이 사라지는 대신, 교체 순간 글꼴이 바뀌며 살짝 어긋나 보일 수 있다(FOUT).
  • optional: 성능을 우선한다. 폰트가 아주 빨리 오지 않으면 이번 방문에는 대체 글꼴로 그냥 두고 넘어간다. 화면 흔들림이 가장 적지만, 웹폰트가 적용되지 않는 방문이 생길 수 있다.

적용 전후, 무엇을 확인해야 하나

최적화는 '했다'가 아니라 '줄었다'로 확인해야 한다. 각 단계 전후로 같은 지표를 보면, 어디서 얼마나 가벼워졌는지 눈으로 잡힌다. 브라우저 개발자 도구만으로 대부분 확인된다.

순서를 지키는 이유가 여기서 분명해진다. 서브셋과 unicode-range로 '내려받는 양'을 줄이고, woff2로 '같은 양을 더 작게' 만들고, font-display로 '기다리는 동안의 경험'을 다듬는다. 앞 단계를 건너뛰고 font-display만 손대면 화면 경험은 나아져도 파일은 여전히 무겁다. 네 단계는 서로를 대체하지 않고 쌓인다.

  • 개발자 도구의 네트워크(Network) 탭에서 폰트 파일의 전송 용량과 개수를 본다. 서브셋·woff2 적용 후 이 숫자가 줄었는지가 가장 직접적인 증거다.
  • 같은 탭에서 폰트가 페이지 로딩의 어느 시점에 요청되는지, 첫 화면에 불필요한 조각까지 내려받고 있지 않은지 확인한다(unicode-range 효과).
  • Lighthouse 같은 성능 측정 도구로 첫 콘텐츠가 뜨는 시점과 화면 흔들림(레이아웃 이동) 지표를 적용 전후로 비교한다. font-display 선택의 효과가 여기에 드러난다.
  • 느린 회선을 흉내 내는 옵션(네트워크 스로틀링)으로, 글자가 뜨는 순간이 방문자에게 어떻게 보이는지 눈으로 확인한다.

자주 묻는 질문

Pretendard와 Noto Sans KR 중 무엇이 더 가볍나요?

원본 전체를 그대로 불러오면 둘 다 무겁고, 어느 쪽이 '본질적으로 가볍다'고 말하기는 어렵습니다. 실제 무게를 가르는 것은 폰트 이름이 아니라 서브셋과 로딩 방식입니다. 같은 Pretendard라도 동적 서브셋으로 필요한 글자만 내려받으면, 전체를 통째로 부르는 다른 폰트보다 훨씬 가볍게 동작합니다. 폰트 선택은 디자인 기준으로 하고, 무게는 이 글의 네 단계로 잡는 편이 맞습니다.

Google Fonts처럼 CDN에서 불러오면 최적화가 다 되어 있나요?

부분적으로 그렇습니다. Google Fonts는 한글 폰트를 unicode-range로 쪼개고 woff2로 제공하므로, 2·3단계는 상당 부분 적용된 셈입니다. 다만 font-display 지정이나, 내 사이트에 꼭 필요한 글자 범위에 맞춘 세밀한 조정은 직접 챙겨야 합니다. 로딩 시점을 더 통제하고 싶다면 폰트를 자체 호스팅해 직접 설정하는 방법도 있습니다.

서브셋을 하면 안 쓰던 글자가 화면에서 깨지지 않나요?

정적 서브셋에서는 그럴 수 있습니다. 폰트에 담지 않은 글자가 등장하면 그 글자만 대체 글꼴로 보입니다. 그래서 문구가 고정된 페이지에는 정적 서브셋이 안전하지만, 방문자가 입력하는 게시판·후기·검색처럼 어떤 글자가 나올지 모르는 영역에는 동적 서브셋이나 전체 폰트를 쓰는 것이 안전합니다.

font-display는 swap과 optional 중 무엇을 쓰는 게 좋나요?

사이트 성격에 따라 다릅니다. 브랜드 글꼴을 반드시 보여주고 싶다면, 글자가 잠깐 안 보이는 구간을 없애는 swap이 무난합니다. 로딩 안정성과 속도가 더 중요하고 글꼴이 잠깐 대체돼도 괜찮다면 optional이 화면 흔들림을 가장 줄여줍니다. 둘 다 글자가 안 보이는 순간(FOIT)을 피한다는 목적은 같습니다.

그냥 시스템 폰트만 쓰면 이 고민이 사라지지 않나요?

맞습니다. 방문자 기기에 이미 깔린 시스템 폰트만 쓰면 내려받을 폰트 파일이 없어 가장 가볍습니다. 다만 기기·운영체제마다 글꼴이 달라 브랜드의 인상을 일정하게 유지하기 어렵습니다. 디자인 일관성을 어느 정도 포기하는 대신 성능을 얻는 선택이며, 그 균형이 맞는 사이트라면 충분히 합리적입니다.

폰트 로딩 전략은 화면을 그린 뒤 덧붙이는 게 아니라 설계 단계에서 정할 일입니다. Karkium은 웹 제작에서 이 과정을 기본으로 다룹니다.

다른 글 보기

홈페이지 제작 문의하기