그간 내 블로그에 사용하던 테마가 마음에 안 들어서 본문에 더 집중할 수 있는 깔끔한 테마를 찾다가 결국 못찾고 새로 만들기로 했다. 그것도 이런저런 핑계로 계속 미루다가 이번에야 완성했지만 말이다. 여하튼, 그래도 이쪽 업계에서 일한 게 몇 년인데 너무 대충 만들면 창피할 것 같아서 이래저래 고민을 좀 하며 만들었다. 그 과정에서 몇 가지 배운 점이 있어 정리해보고자 한다.
1. 웹 폰트: 어쩌면 2,350자는 많을지도 모른다
글자 하나하나의 벡터 정보를 저장하는 글꼴 파일의 특성상 표현해야 하는 글자가 많아지면 용량이 그에 비례하여 늘어난다. 이 부분이 웹 폰트를 사용할 때 한국 사람이 가장 크게 좌절하는 부분인데, 바로 한글이 표현할 수 있는 글자는 총 1만 1,172개로 글꼴로 만들기에는 많아도 너무 많기 때문이다. 사실 여기에 더 안 좋은 부분은 한자와 일본어까지 고려해야 한다는 점이다. 구글에서 배포하는 Noto Sans를 보면 영문 전용 글꼴 파일의 용량은 203K, 한국어/일본어/중국어를 포함한 글꼴 파일의 용량은 16.5MB에 달한다.
TTF 글꼴 파일의 용량을 줄일 수 있는 가장 확실하고 효율적인 방법은 글꼴이 표현하는 글자의 수를 줄이는 것이다. 그래서 보통 웹 폰트로 만들 때는 일본어와 중국어는 제외하고, 한국어도 1만 1,172자가 아닌 완성형 2,350자만 포함한다. 여기에 로마자와 기호 몇 가지를 포함해서 글꼴을 만들면 3.6MB가 1.9MB 정도로 줄어든다. 이 파일을 예전 IE에서 지원하는 eot 포맷으로 변환하면 1.9MB, 상대적으로 최근 브라우저에서 지원하는 woff 포맷으로 변환하면 686K가 되는데 많이 줄어들긴 했지만 여전히 작지 않은 용량이다.
그때 지금 이 글꼴을 만들려는 이유가 내 블로그 때문이라는 생각이 들었다. 즉 콘텐츠 생산자는 나 혼자 밖에 없다는 뜻이다. 모든 사람에게는 언어 습관이라는 게 있기 마련인데 내가 정말 완성형 2,350자를 모두 다 사용할까? 그래서 찾아 본 완성형 한글의 목록에는 내가 절대로 사용하지 않을 것 같은 글자가 꽤 포함되어 있었다. 바로 글자 샘플을 뽑기로 하고 기반 데이터는 10년 넘게 운영해오는 이 블로그의 글과 댓글로 정했다. 비록 글을 자주 썼던 건 아니지만 그래도 10년이 넘었으면 적어도 앞으로도 새로운 글자를 쓸 일은 없겠다 싶었다.
앞서 완성형 한글과 로마자, 자음, 모음, 기호를 포함했을 때 글자 수가 2,486자였는데 내 블로그를 샘플로 뽑은 전체 글자 수는 1,595자였다. 이번엔 TTF와 eot 파일의 용량이 1.1M로, woff는 423K로 줄었다. 더 이상 줄이는 것은 무리라서 이 정도면 되겠다 싶었다.
2. 웹 폰트: WOFF2 = AWESOME!
웹 폰트를 만들어준다는 각종 제너레이터가 많지만, 대부분 상대적으로 새 포맷인 woff2는 포함하지 않고 만들어준다. 그런데 woff2를 검색해보면 아주 혹할만한 설명을 볼 수 있다.
WOFF2 is a font format that provides, on average, a 30% reduction in file size, thus helping Web fonts load more quickly in compatible browsers. WOFF2 fonts are automatically included when publishing new Fonts.com Web Fonts projects.
그렇다. 파일 사이즈가 30%나 줄어든다! 당장 실험을 안해볼 이유가 없어서 앞서 만든 TTF 파일을 woff2로 바꿨더니 포맷만 바꿨을 뿐인데 파일의 용량이 276K로 줄었다!
웹 폰트 포맷의 브라우저 지원 현황을 보면 IE까지 감안한다해도 eot와 woff2 두 파일만 있어도 충분할 것 같다. Node가 있는 환경에서 ttf2woff2 CLI 도구를 설치하면 커맨드라인에서 간단히 TTF 포맷을 woff2로 변환할 수 있다. 참고로 나는 폰트를 만들고 이를 eot, woff, woff2 등으로 매번 변환하기가 귀찮아서 간단한 CLI 도구를 직접 만들어서 사용했다.
3. 웹 폰트: 같은 해상도라도 윈도우에서 더 안 좋게 표현된다
처음 CSS를 만들 때는 맥 환경만 고려하여 작업을 했다. 맥북 프로에 일반 모니터를 연결해서 사용하기 때문에 레티나 환경이 아닌 윈도우라 해도 적어도 기준이 됐던 크롬 브라우저에서는 비슷하게 보이리라 생각했는데 큰 착각이었다. 일반적인 맥 환경의 크롬에서는 레티나 디스플레이가 아닌 모니터에서도 현재 블로그의 글씨 크기를 80%로 줄여놓고 봐도 읽는데 무리가 없으며 75%로 줄여도 글자를 인식할 수 있다.
윈도우에서는 사정이 다르다. 크롬과 Edge 브라우저 양쪽 모두 기본 크기일 경우 글자를 읽기엔 불편했는데, 특히 Edge 브라우저는 다음과 같이 아예 글자가 깨져버리는 현상이 발생했다.
그래서 윈도우에서는 글자 크기를 10% 키웠더니 그제서야 글자가 정상으로 보였다. 이제 글자가 깨지진 않지만 여전히 맥과 비교하면 글자가 더 가늘게 표현되었다.
이에 관해 구글링을 해보니 몇 가지 핵이 있었는데 그 중 눈에 띄지 않을 수준으로 회전을 시켜서 화면을 더 선명하게 그리게 하는 방법과 글자 밑에 반투명한 그림자를 깔아서 글자를 더 굵고 진하게 보이게 하는 방법을 적용했다.
또한 크롬과 파이어폭스 브라우저에서는 글자에 안티앨리어싱이 적용되도록 설정했다.
이렇게 적용하고 나면 글자가 훨씬 진해져서 더 보기 편해진다. 비교를 위해 앞에서 글자를 110%로 키웠던 화면을 앞에 두었다.
다만, 캡션이나 각주 등 본문 글자보다 작게 표현되는 텍스트는 윈도우에서 글자가 깨지는 문제가 동일하게 발생해서 아예 다른 sans-serif 계 글꼴을 사용하도록 했다.
4. 웹 폰트: 생략된 문자 처리
앞서 웹 폰트의 용량을 줄이기 위해 자주 사용하지 않는 문자는 글꼴에서 생략했다고 말했는데, 만일 그렇게 생략된 문자가 콘텐츠에 포함되어 있다면 어떻게 표현될까? 결론부터 말하면 OS마다 다르다. “OS마다”라고 표현한 이유는 같은 크롬 브라우저라도 윈도우즈에서는 내가 설정한 글꼴 중 “NanumMyeongjo” 다음에 정의한 serif를 폴백(fallback)으로 사용해 다른 글꼴로 해당 글자를 어떻게든 표현해 낸 반면, 맥에서는 다음과 같이 그냥 깨진 문자로 보여주었다.
이런 문제를 해결하기 위해 간단한 자바스크립트 코드를 추가했다. 본문에서 허용하는 문자 범위를 벗어나는 문자가 감지되면 해당 부분을 span.safe-char 노드로 감싸버리는 것이다. 그리고 span.safe-char 노드에는 웹 폰트가 아닌 안전한 시스템 serif 글꼴만 사용하도록 했다. 그 결과 맥에서도 한자 등 웹 폰트에 없는 글자가 정상적으로 표현되었다. 같은 로직을 서버 사이드에서 처리할 수도 있겠지만, 아무래도 DOM을 파싱하고 처리하는 게 자바스크립트보다는 번거로울 것이다. 안전한 문자 처리가 된 글은 ReactJS 둘러보기에서 볼 수 있다.
또 하나 주의할 것은 스페이스, 줄바꿈과 같은 공백 문자이다. 처음 웹 폰트를 만들 때는 데이터 크기를 조금이라도 줄이기 위해 글꼴 정보가 필요없는 공백 문자를 모두 삭제하여 최적화했었다. 그랬더니 MS 계열 브라우저에서 간혹 깨진 글자가 아무 것도 없는 곳에서 나타났다.
이 영역을 검사해보면 다음과 같이 텍스트 노드는 “달랐다.”에서 분명히 끝나있었다. 그런데도 위와 같이 “다.” 뒤에 깨진 문자가 나타난 것이다.
구글링을 해도 도저히 답을 알 수 없었는데 여러 실험을 해본 결과 문제는 <br />부분이었다. 다른 브라우저와 달리 MS 계열 브라우저는 아마도 <br />을 처리할 때 그 자리에 줄 바꿈 문자(n)를 출력하는 듯 하다. 그런데 내가 만든 웹 폰트는 최적화를 위해 공백 문자를 모두 지워버렸기 때문에 줄 바꿈 문자를 깨진 문자로 표현한 것이다.
한자도 스페이스도 폴백으로 잘 처리해주더니 유독 줄 바꿈 문자에만 깐깐한 이유는 알 수 없지만 어쨌든 할 일은 명확했다. 직접 만든 웹 폰트 작성 도구를 조금 수정하여 공백 문자는 반드시 글꼴에 남기도록 하고, 공백 문자에 줄 바꿈 문자와 캐리지 리턴(r)을 함께 매핑시켜 새로운 글꼴을 만들어 업로드하자 문제가 해결됐다.
5. 웹 폰트: 굵은 글꼴은 필요 없을지도 모른다
기본 글꼴을 바탕으로 굵거나 기울어 진 글꼴을 에뮬레이션 해주는 윈도우와 달리 맥에서는 각 글꼴 모양마다 글꼴 파일이 따로 마련되어 있어야 한다. 가끔 굵은 글꼴을 본문에서 사용하는데, 상대적으로 그리 중요하지 않은 굵은 글꼴을 표현하기 위해 수백 KB에 달하는 글꼴 파일을 추가해야 하는지 고민이 되었다. 조사 결과 크롬 웹 브라우저는 맥에서도 윈도우처럼 굵은 글꼴이 없으면 웹 폰트의 굵은 글꼴을 에뮬레이션 해주었다.
그리고 구글 애널리틱스의 통계를 살펴 보면, 다행히 내 블로그에 방문하는 독자 70% 정도는 크롬 웹 브라우저를 사용하며, 운영체제로 봐도 윈도우즈 사용자가 절반 가량 되기 때문에 굵은 글꼴을 위한 웹 폰트 파일은 따로 만들지 않기로 했다. 사실 굵은 글꼴이 없어도 본문을 보는데 큰 무리가 없다는 것도 이유였다.
6. 한글에는 word-break: keep-all이 잘 작동하지 않는다.
이 프로퍼티는 줄 바꿈의 기준을 설정한다. 예를 들어 어떤 페이지에서 영문 5자까지 한 줄로 표현할 수 있다고 가정할 때 “The moon”이라는 텍스트는 공백 포함 8자이므로 반드시 줄바꿈을 해야한다. 그런데 어디서 하면 좋을까? 순전히 글자수로만 나눈다면 아마 다음과 같이 되어야 할 것이다.
그렇지만 실제로는 다음과 같이 되는 게 일반적이다.
이런 현상이 일어나는 이유는 브라우저가 단어가 갈라지는 기준(word-break 속성)에 맞추어 줄을 나누기 때문이다. 아마도 왕년에 게시판 등을 만들 때 긴 단어나 링크가 주어진 영역을 벗어나지 않게 하기 위해 word-break: break-all을 써본 이도 있을 것이다. 한국어에 한해서는 기본적으로 break-all이 적용된 듯 하게 동작하기 때문에 간혹 다음과 같이 제목이 보기 싫게 잘리는 경우가 있다.
이런 문제를 해결하기 위해 제목에 한해서는 단어를 보존해주도록 word-break: keep-all로 설정하면 똑같은 레이아웃에서 제목이 다음과 같이 줄바꿈된다.
모든 브라우저에서 이렇게 잘 적용됐으면 좋았겠지만 안타깝게도 웹킷 계열이 아닌 주요 브라우저들은 한국어에 대해 word-break: keep-all이 동작하지 않고 설정과 관계없이 단어 중간을 자른다. 해결 방법이 없는 것은 아니다. 다행히 한국어 문제가 생기는 경우는 인라인 요소에 사용했을 때뿐이었고, 나는 이 속성을 글 제목에만 사용했으므로 간단하게 제목을 감싼 앵커 요소에 블럭 디스플레이 속성을 주어 문제를 해결했다.
보너스 트랙
본문에서 언급했던 직접 만든 간단한 CLI 도구의 초기 버전을 GitHub과 npm에 공개했다. 개인적으로 쓰던 걸 이 글과 함께 공개하려고 대충 손본 거라 아직 다듬어야 할 부분은 많겠지만 참고삼아 보기에는 괜찮을 것 같다.
원문: 코드쓰는사람