한글 웹 폰트 경량화해 사용하기

웹 폰트란?

웹 폰트란 간단히 말해서 폰트파일(eot, woff 등)을 브라우저가 서버로부터 내려받아 사용하는 폰트를 말합니다. 이용자 컴퓨터에 설치돼 있지 않아도 폰트가 동작하기 때문에 조금 더 미려한 디자인을 가능하게 합니다.

Google Fonts
<그림 1.google fonts>

Google Fonts의 서비스를 이용하면 사용할수 있습니다만 조금 아쉬운 점이 있습니다. 바로 구글의 폰트 서버를 이용해야 한다는 점인데요. 간단하고 편한 방법이긴 하지만 구글 서버의 응답이 늦거나 어떤 장애가 발생했을 때 그로 인한 이슈가 뒤따른다는점이죠. 그래서 직접 웹 폰트를 내려받아 사용하고자 합니다.

예제 폰트

여기서는 예제로 Noto Sans CJK를 사용합니다. Noto Sans CJK는 구글과 어도비가 합작한 중국어, 일본어, 한국어를 모두 완벽히 지원하는 웹 폰트입니다.

Noto Sans CJK 다운로드

Noto Sans CJK는 공식 홈페이지에서 내려받을 수 있습니다. CJK는 중국(China), 일본(Japan), 한국(Korea)의 준말입니다. NotoSans는 거의 모든 언어를 지원하지만, 서비스 특성상 모든 언어를 지원할 필요는 없으므로 CJK KR 버전을 내려받습니다.

NotoSans CJK KR 파일 리스트
<그림 2.notosans cjk kr 파일 리스트>

압축을 풀고 용량을 확인하는 순간, 엄청난 크기에 절망합니다. 웹에서는 단 1MB도 큰 단위이기 때문에 웹 폰트를 사용할 엄두가 나지 않습니다.

Subset(and Subsetting)

Google의 Subset 개념도
<그림 3.google의 subset 개념도>

아직 포기하기엔 이릅니다. 웹 폰트에는 서브셋이라는 개념이 있습니다. 서브셋은 말 그대로 특정 폰트의 하위 집합을 뜻합니다. 따라서 필요한 하위 집합만을 추린다면 파일의 용량은 처음보다 아주 작아질 것입니다.

Google의 서브셋 기능

Google Font 역시 서브셋 기능을 제공하고 있습니다.

NotoSans Subset 다운로드
<그림 4.notosans subset 다운로드>

CJK 다운로드 페이지에서 this folder 링크를 클릭합니다. 그리고 NotoSansKR-*.otf 한국어 서브셋 파일을 내려받고 확인합니다.

NotoSans KR 파일 리스트
<그림 5.notosans kr 파일 리스트>

이전 파일(약 16MB)과 비교하여 확실히 파일의 용량이 줄었습니다. 하지만 여전히 부담되는 용량입니다. 더 용량을 줄일 수 없을까요?

직접 Subset 지정하기

완성형일 경우 엄청난 양의 한글이 필요하지만, 사실 모든 문자셋을 사용하진 않습니다. KS X 1001 표준에는 자주 쓰이는 한글 2,350자를 정의하고 있습니다. 이 한글만 추려낸다면 용량을 많이 줄일 수 있을 것 같습니다.

서브셋 폰트 메이커와 WOFF컨버터
<그림 6.서브셋 폰트 메이커와 woff컨버터>

이 문제와 관련된 유용한 애플리케이션을 찾았습니다. 서브셋 폰트 메이커WOFF 컨버터가 바로 그것입니다. 이 두 애플리케이션을 설치합니다.

서브셋 폰트 메이커 파입 입력 폼
<그림 7.서브셋 폰트 메이커 파입 입력 폼>

그리고 서브셋 폰트 메이커에 NotoSans 폰트와 새로운 파일의 경로를 설정합니다.

서브셋 폰트 메이커 폰트 지정 폼
<그림 8.서브셋 폰트 메이커 지정 폼>

그리고 폰트에서 남기고자 하는 한글(및 영어, 숫자, 특수문자)를 입력하고, WOFF 컨버터 실행에 체크합니다.

폰트 지원 여부

EOT는 IE에서만 지원하는 문자 포멧입니다. WOFF또는 OTF는 모든 브라우저에서 지원합니다.

생성 시작 버튼을 클릭하면 폰트 파일이 생성된 후 WOFF 컨버터가 실행됩니다. 자동으로 경로가 입력되므로 별다른 설정 없이 변환시작 버튼을 선택해 변환합니다.

컨버터된 NotoSans KR 파일 리스트
<그림 9.컨버터된 notosans kr 파일 리스트>

생성된 파일을 확인하면 4.7MB에서 200KB ~ 400KB 사이로 용량이 작아진걸 확인할 수 있습니다.

컨버터된 NotoSan KR 파일의 전체 용량
<그림 10.컨버터된 notosan kr 파일의 전체 용량>

파일의 전체 용량도 이전 폰트 파일 1개의 용량 만큼 작아졌습니다. 브라우저는 자신이 지원하는 폰트 파일만 요청할 것이므로 폰트의 모든 굵기를 사용한다면 최대 약 1.6MB 정도 요구될 것 같네요. 보통 3~4가지의 굵기를 추려서 사용하므로 이 정도면 웹에서 사용해도 큰 부담이 없을 것 같습니다.

사용해보기

변환한 파일이 제대로 동작하는지 한번 사용해 보겠습니다.

@font-face {
    font-family: 'Noto Sans';
    font-style: normal;
    font-weight: 100;
    src: local('Noto Sans Thin'), local('Noto Sans Thin'), local('Noto Sans Thin');
    src: url(NotoSansKR-Thin-subset.eot);
    src: url(NotoSansKR-Thin-subset.eot?#iefix) format('embedded-opentype'),
    url(NotoSansKR-Thin-subset.woff) format('woff'),
    url(NotoSansKR-Thin-subset.otf) format('truetype');
}

@font-face {
    font-family: 'Noto Sans';
    font-style: normal;
    font-weight: 300;
    src: local('Noto Sans Light'), local('Noto Sans Light'), local('Noto Sans Light');
    src: url(NotoSansKR-Light-subset.eot);
    src: url(NotoSansKR-Light-subset.eot?#iefix) format('embedded-opentype'),
    url(NotoSansKR-Light-subset.woff) format('woff'),
    url(NotoSansKR-Light-subset.otf) format('truetype');
}
... 이하 생략 ...

먼저 css 파일에서 웹 폰트를 지정합니다.

<style>
  span {font-family: 'Noto Sans';font-size: 20px}
</style>
<span style="font-weight: 100">모든 인간은 태어날 때부터 자유로우며 그 존엄과 권리에 있어 동등하다. 12345567890, ABCDEFG<br />
<span style="font-weight: 300">모든 인간은 태어날 때부터 자유로우며 그 존엄과 권리에 있어 동등하다., 12345567890, ABCDEFG<br />
<span style="font-weight: 350">모든 인간은 태어날 때부터 자유로우며 그 존엄과 권리에 있어 동등하다., 12345567890, ABCDEFG<br />
<span style="font-weight: 400">모든 인간은 태어날 때부터 자유로우며 그 존엄과 권리에 있어 동등하다., 12345567890, ABCDEFG<br />
<span style="font-weight: 500">모든 인간은 태어날 때부터 자유로우며 그 존엄과 권리에 있어 동등하다., 12345567890, ABCDEFG<br />
<span style="font-weight: 700">모든 인간은 태어날 때부터 자유로우며 그 존엄과 권리에 있어 동등하다., 12345567890, ABCDEFG<br />
<span style="font-weight: 900">모든 인간은 태어날 때부터 자유로우며 그 존엄과 권리에 있어 동등하다., 12345567890, ABCDEFG

그리고 이 폰트를 사용해 HTML에 적용합니다.

NotoSans 폰트 사용 결과
<그림 11.notosans 폰트 사용 결과>

끝으로

매번 웹 폰트를 사용할 때마다 위에서 소개한 서브셋 폰트 메이커와 WOFF 컨버터를 이용해 필요한 문자만 추출하는 작업을 반복할 순 없을 것 입니다. 서비스의 특성에 따라 필요한 문자셋도 다를 것이며 간단해 보이지만 의외로 반복적이고 따분한 작업입니다. 이를 간단하게 자동화하거나 문자셋을 몇 가지 패턴으로 나눠 중앙 서버에서 제공해주는 방법을 고려해보는 게 좋을 것 같습니다. 이를 위해선 현재 애플리케이션의 원리를 분석하여 환경에 맞는 애플리케이션을 새롭게 개발해야 할 수도 있습니다.(원리는 단순히 유니코드를 비교하여 필터링하는 것으로 보입니다.)

이것으로 필요한 문자만 나두고 나머지를 전부 제거하는 방식으로 웹 폰트 용량을 경량화 하는 방법에 대해 알아봤습니다. 만약 폰트에 없는 문자를 작성하게 되면 폰트가 깨질 것입니다. 따라서 댓글과 같이 어느 나라 유저가 어떤 문자를 작성할 지 모르는 기능에는 이 방식으로 웹 폰트를 지원하기는 힘들 것입니다. 하지만 사이트의 타이틀, 설명구, 메뉴, 아티클 등에는 이러한 방식으로 경량화하여 웹 폰트를 충분히 지원할 수 있을 것 같습니다.

잘못된 폰트 파일이 웹상에 퍼질까봐 노파심에 파일을 공개적으로 공유하지 않았지만, 생각지 못하게 경량화한 폰트 파일을 달라는 요청이 많아서 깃허브 저장소에 올려두었으니 참고하시길 바랍니다.

버그

인터넷 익스플로러(이하 IE)에는 다양한 웹 폰트 버그가 있기 때문에 서비스 정책상 구 버전 IE를 지원해야 한다면 웹 폰트를 사용하기 싫어질 수 있습니다. 제가 겪는 문제를 이 곳에 조금씩 정리해나갈 생각이지만 잠재적인 버그가 워낙 많기 때문에 이 외에도 다양한 문제를 마주할 수 있습니다.

IE8에서 가중치(weight)가 동작하지 않는 문제

첫 번째로 font-face를 이용해 다양한 가중치를 선언하면 IE8에서 특정 가중치가 동작하지 않는 문제가 있습니다.

@font-face {
    font-family: 'Noto Sans';
    font-style: normal;
    font-weight: 300;
    src: local('Noto Sans Light'), local('Noto Sans Light'), local('Noto Sans Light');
    src: url(./NotoSansKR-Light.eot);
    ... 생략 ...
}

@font-face {
    font-family: 'Noto Sans';
    font-style: normal;
    font-weight: 400;
    src: local('Noto Sans Regular'), local('Noto Sans Regular'), local('Noto Sans Regular');
    src: url(./NotoSansKR-Regular.eot);
    ... 생략 ...;
}

.f {font-family: 'Noto Sans'}
.fw300 {font-weight: 300}
.fw400 {font-weight: 400}
.fw500 {font-weight: 500}
.fw700 {font-weight: 700}

보통 위와 같은 방식으로 font-face를 선언하고 가중치를 이용해 다양한 굵기의 폰트를 사용합니다.

Firefox와 IE8의 폰트 출력 결과
<그림 12.firefox와 ie8의 폰트 출력 결과>

위 그림을 보면 파이어폭스에서는 의도한대로 출력되지만 IE8에서는 font-weight: 300, 400, 500으로 선언한 폰트가 동일한 굵기로 출력되는 것을 볼 수 있습니다. 이 문제는 하나의 폰트 명으로 묶지 않고 각각 폰트 명을 지정하는 방법으로 회피할 수 있습니다.

.fw300 {font-family: 'Noto Sans Light'}
.fw400 {font-family: 'Noto Sans Regular'}
.fw500 {font-family: 'Noto Sans Medium'}
.fw700 {font-family: 'Noto Sans Bold'}

위 코드를 IE8로 실행해보면 다음과 같이 출력됩니다.

IE8의 폰트 출력 결과
<그림 13.ie8의 폰트 출력 결과>

IE8의 버그를 회피하고자 폰트 명을 여러개로 분할했습니다. 개발이나 유지보수 차원에서 그다지 좋은 방식은 아닌것 같아 아쉽습니다. 이와 관련된 버그는 Using multiple weights and styles에 잘 정리돼 있습니다.

IE8에서 특수 문자가 비정상적으로 출력되는 문제

위에서 서브셋을 직접 지정하는데 NotoSansKR-*.otf 파일을 사용했습니다. 추출한 폰트 파일을 IE8에서 사용하면 특수문자가 비정상적으로 출력되는 문제가 있습니다.

Firefox와 IE8의 특수문자 출력 결과
<그림 14.firefox와 ie8의 특수문자 출력 결과>

키보드로 입력 가능한 특수문자인 -(dash), |(vertical bar) 등이 잘못 렌더링 되는 문제입니다. 아직 정확한 원인은 파악하지 못했지만 폰트 파일과 직접적인 영향이 있는것으로 추측되어 파일을 NotoSansKR-*.otf이 아닌 NotoSansCJKkr-*.otf로 변경하여 다시 추출했습니다.

NotoSansCJKkr은 NotoSansKR에 비해 용량이 3배 이상 많으므로 다양한 문자를 포함하고 있으니 원하는 문자를 추출할 수 있을 것 같았습니다. 추출 후의 파일 용량은 약 2KB 정도 차이 납니다.

IE8의 특수문자 출력 결과
<그림 15.ie8의 특수문자 출력 결과>

새로 추출한 폰트 파일로 변경하고 IE8에서 실행하면 정상적으로 출력됩니다.