지금은 많이 달라졌지만, 처음 이 블로그를 만들 때는 그 당시의 유행을 따라 포스트 제목에 weight가 200인 폰트를 사용하고자 했다. 그리고 본문은 일반적인 18px의 weight 400으로 설정했다. 그러자 자연스레 얇고 큰 폰트와 상대적으로 굵고 작은 폰트의 획 굵기를 시각적으로 같아 보이게 하고 싶었다.

위 이미지1처럼 대강 큰 텍스트와 작은 텍스트, 둘의 조합을 만드는 건 쉬웠다. 하지만 블로그라는 웹 기반 공간의 특성상 <h1>부터 <h6>까지의 스타일이 필요했고, 여기에 포스트 제목과 본문까지 더해서 총 8개의 위계를 서로 다른 텍스트 스타일로 표현해야 했다. 처음부터 포스트 제목 스타일은 weight가 200이라고 정해버렸으므로 그 아래의 위계인 Heading들이 블로그 제목보다 더 두꺼운 건 어쩐지 옳지 않게 느껴졌다.

결국, 나는 모든 텍스트가 같은 굵기로 보이도록 해야 한다는 강박에 이르렀다. 하지만 폰트의 자족과 크기만으로는 불가능했기에 색상이라는 변수를 끌어들이게 되었다. 같은 자족의 두 폰트의 크기가 다를 때 더 큰 쪽의 폰트에 약간 밝은 색을 지정하면 마치 두 폰트가 절대적으로 같은 무게감을 가진 듯이 눈속임을 할 수 있었기 때문이다. 하지만 당연하게도 최소 8개 위계를 오로지 크기로만 구분하려는 시도는 성공하지 못했고 결과적으로 전혀 다른 타이포그래피 전략을 선택했지만, 초기에 시도했던 폰트의 굵기, 크기, 색상이라는 삼박자가 시각 보정에 미치는 영향은 꽤 흥미로웠다.

UI 디자이너인 나는 Pixel precision2의 신봉자이기 때문에 이전까지는 antialias를 진지하게 생각해본 적이 없었다. 문자의 획에 가장 가까운 굵기인 1px border는 명백히 Pixel로 딱 떨어지는 UI 요소이고, aliased 요소는 색상이 그 굵기의 느낌에 영향을 크게 미치지 않기 때문이다. 이런 착시 현상에는 여러 이유가 있을 텐데, 그 중 한 가지는 색상이 밝아짐에 따라 antialias 된 외곽 Pixel의 색상이 배경으로 인지될 가능성이 커지기 때문이 아닐까 추측해본다.

이유가 무엇이든 간에 “색이 밝아질수록 체감하는 선의 굵기가 얇아진다”는 원리가 폰트에서 발견된 점은 내게 무척 재미있었다. 일반적인 UI 요소는 그 전체 크기와 세부 요소 간에 상관성이 거의 없다. 버튼 크기가 두 배가 된다고 그 안의 텍스트나 외곽선이 두 배가 되진 않는다. 오히려 이 비례를 정확하게 맞춰야 하는 @2x, xxxhdpi 등의 리소스 자르기는 UI 디자이너에게 무척 귀찮은 작업 중에 하나다. 반면에 폰트의 굵기는 폰트의 크기에 비례한다. 이런 특성 때문에 같은 자족의 폰트를 사용했을 때 폰트의 크기가 두 배면 폰트의 굵기도 두 배가 된다. 디스플레이 상에서 폰트 크기가 18px일 때 획의 굵기가 2px이라고 가정한다면, 폰트 크기가 22px일 때는 그 굵기가 2.444px3이다. 즉 크기가 22px이면서 획의 두께가 2px인 폰트는 없다. 현대의 기술 수준에서 폰트 제작 방식과 유통 방법이 가져오는 필연적인 제한이다. 하지만 색상, 엄밀히 구분하자면 명도라는 요소가 개입하면 얼마간은 기술적 제약을 뛰어넘어 시각 뇌를 속일 수 있다.

그렇다면 이는 얼마까지 유효할까? 명도와 폰트 크기, 획의 굵기는 어떤 관계가 있는 걸까? 이런 호기심에서 출발해 아래와 같은 가설을 세우고 이를 검증하기 위한 작은 실험을 해보았다.

가설

디스플레이상에서 시각이 인지하는 폰트의 굵기는 폰트의 명도에 영향을 받으며, 폰트의 명도가 밝아질 수록 획이 얇게 보인다. 이 때 폰트 크기와 명도, 체감하는 획의 굵기는 유의미한 상관관계가 있다.

실험4

주의: 아래 내용에 삽입된 이미지는 크기에 민감하게 영향을 받으므로 가로 너비가 700px 이하의 기기에서는 부정확하게 보인다.

먼저 이 블로그의 폰트 크기인 18px의 텍스트를 #333으로 놓고 그보다 3px 큰 21px 텍스트의 색상을 점점 밝게 변화해가며 비교해보았다.

이미지 1-1. 다른 명도의 체감 획 굵기 차이

다소 큰 폭으로 명도를 조정했을 때 세 번째 그룹(18px:#333, 21px:#555)이 가장 획의 굵기가 균등해 보인다. #333을 명도로 환산하면 (51 × 100)/256 = 약 19.922% 이고, #555는 (85 × 100)/256 = 약 33.203% 이므로 약 13%의 명도 차이가 있다.

같은 조건에서 폰트 크기만 달리해 21px과 24px을 비교해보았다.

이미지 1-2. 다른 명도의 체감 획 굵기 차이

24px이 약간 밝아 보이긴 하지만 이번에도 세 번째 그룹이 가장 안정적으로 보인다. 그렇다면 폰트 크기가 3px 정도 차이 날 때 더 큰 폰트의 명도가 약 13% 밝으면 두 폰트의 굵기가 일정해 보이는 걸까? 이번에는 12px, 15px, 18px, 21px, 24px의 여섯 가지 크기의 텍스트에 모두 같은 색을 적용한 것과 폰트 크기가 커질 수록 약 13% 정도 밝아지는 조합을 비교해 보았다.

이미지 2. 크기가 점점 커지는 폰트와 그에 따른 명도 변화

텍스트가 모두 같은 색인 그룹(위)은 폰트의 크기가 커질수록 폰트의 색상도 점점 진해진다는 느낌이지만, 명도가 일정하게 밝아지는 그룹(아래)은 폰트의 크기가 커질수록 폰트가 옅어진다는 느낌이 든다. 오호라.

앞선 세 이미지를 통해 두 가지 사실을 발견했다.

  1. 두 폰트의 색상이 #333, #555 일 때 18px과 21px, 21px과 24px, 12px과 15px 모두 획의 굵기가 균등해 보였다.
    이미지 3-1. 같은 굵기로 보이는 두 폰트
  2. 21px과 24px 폰트가 각각 #333, #555 일 때는 획의 굵기가 같아 보이는 반면, 같은 명도 차이인 #999, #bbb 일 때는 24px인 폰트가 밝아 보인다.
    이미지 3-2. 밝기가 달라 보이는 두 폰트

두 폰트의 크기 차가 일정하다면 절대적인 크기는 중요하지 않지만5 이 두 폰트 간에 명도 차이는 폰트의 색상이 밝아질수록 줄어드는 듯하다.

과연 그런지 확인해보기 위해 이번에는 폰트의 크기 차이를 그대로 3px로 유지하면서, 두 폰트가 12px, 15px일 때 굵기가 같아 보이는 색상 #555#6b6b6b을 기준 색으로 놓고 다양한 크기의 폰트를 비교해보았다.

이미지 3-3. 고정된 명도와 점점 커지는 폰트 크기

폰트의 절대적인 크기가 변함에도 두 폰트가 주는 획 차이의 이미지는 거의 같은 것으로 보아 폰트의 크기는 체감하는 획 굵기에 영향을 미치지 않는다고 보았다. 그렇다면 서로 다른 크기의 폰트의 굵기가 일정하게 느껴지는 데는 두 폰트의 크기 차, 두 폰트의 색상, 두 폰트의 명도 차 - 이 세 가지 요소가 작용한다. 세 요소를 한 번에 생각하려면 연산이 무척 복잡해지므로 두 폰트의 크기 차는 3px로 고정했을 때 색상 차가 어떤 관계가 있는지 알아보았다.

먼저 위에서 찾은 #333#555를 RGB 값으로 변환해 점을 찍었다.

이미지 4-1. (51, 85)

마찬가지로 #555#6b6b6b도 차트에 표시했다.

이미지 4-2. (85, 107)

같은 방식으로 #000#111#222#eee까지 두 획의 굵기가 같아 보이는 색상 쌍을 거칠게 뽑아서 그래프로 그려보았다.

이미지 4-3. #000 부터 #eee까지의 색상 쌍

약간 삐뚤빼뚤하지만 일정한 경향성을 띄고 있다. 하지만 이 형태만 가지고는 이 점들이 일차함수로 표현되는지 이차함수로 표현되는지 알 수 없으므로 Linear trend line과 Polynomial trend line을 모두 그려보았다.

이미지 5-1. Linear trend line
이미지 5-2. Polynomial trend line

먼저 Linear trend line에서 가장 멀리 떨어진 (102, 118)을 대상으로 102를 x에 대입했을 때를 보았다.

  • Linear trend line: 0.7534 × 102 + 49.817 = 126.6638
  • Polynomial trend line: 0.0012 × 1022 + 0.4724 × 102 + 60.165 = 120.8346
이미지 6-1. Linear trend line을 따른 (102, 126)
이미지 6-2. Polynomial trend line을 따른 (102, 121)
이미지 6-3. 눈대중으로 맞춘 (102, 118)

이쯤 되면 무엇이 정답이라고 단언하기 어려울 정도로 차이가 근소해졌다. 그럼에도 위 세 이미지 중에서는 Linear trend line에 맞춰본 6-1은 큰 쪽의 폰트가 좀 더 밝아 보인다.

위와 같은 방법을 반복하여 #000부터 #eee까지의 색상 쌍을 다시 정밀히 비교해보았다.

이미지 7-1. `#000`부터 `#eee`까지의 색상 쌍 찾기

위 이미지에서 가운데 분홍 줄의 텍스트들이 Polynomial trend line에서 얻은 y = 0.0012x2 + 0.4724x + 60.165 를 충족하는 값이다. (소수점 이하는 반올림했다) 이를 기준으로 그보다 어둡거나 밝은 폰트 색을 비교해보면서 가장 획의 굵기가 유사하다고 생각하는 쌍에 별표를 쳤다. 그리고 이 결과로 새로운 그래프를 그렸더니 아래와 같았다.

이미지 7-2. 7-1에서 찾은 색상 쌍 그래프

5-2 그래프와 비교했을 때 trend line과 눈으로 뽑은 색상 쌍이 거의 일치한다. 그렇다면 두 폰트 크기의 차가 3px의 두 배인 6px일때는 어떨까? 폰트의 크기 차가 일정할 때 색상 쌍이 일정하게 변화한다면, 마찬가지로 폰트의 크기 차에 따라서도 색상 쌍이 일정한 모양을 그리리라 생각했다.

이미지 8-1. 두 폰트의 크기 차가 6px일때 거칠게 뽑은 색상 쌍

5-2 그래프와 같이 trendline과 각 점들이 완벽히 일치하진 않지만 모두 1 - 3 정도의 오차범위 내에 들어가는 것을 확인할 수 있었다. 이번에는 폰트 크기 차가 1px일때 색상 쌍을 뽑아보았다.

이미지 8-2. 두 폰트의 크기 차가 1px일때 거칠게 뽑은 색상 쌍

위 그래프들과 마찬가지로 기울기가 1보다 작은 양수인 2차 함수 그래프로 표현된다. 7-2, 8-1, 8-2 세 그래프를 겹쳐보았다.

이미지 9. 두 폰트의 크기 차가 각 1px, 3px, 6px인 색상 쌍의 세 그래프

재미있게도 예상보다 일관된 모양의 그래프를 얻었다. 이 교차그래프로부터 다음과 같은 사실을 유추할 수 있었다.

  • 두 폰트의 색상 쌍 그래프는 2차 함수로 표현된다.
  • 두 폰트의 크기 차가 클수록 색상 차도 커진다.
  • 두 폰트의 크기 차에 상관없이 폰트 색상이 밝아질수록 색상 차는 근소해진다.

그렇다면 이제 대략적인 상관관계는 드러났다. 여기서 더 나아가 정확한 공식을 구해보고자 했다. A=B=C일 때, A=C 이므로 n px차의 두 폰트의 색상 쌍을 구하는 함수를 찾아낸다면 이 함수를 두 번 연산했을 때 2n px 차의 두 폰트의 색상 쌍, 세 번 연산했을 때 3n px 차의 색상 쌍을 구해낼 수 있을 것이다. 식으로 나타내면 아래와 같다.

  • fn(x) = y
  • fn(fn(x)) = f2n(x)

먼저 1px 차 폰트의 색상 쌍 함수 f1(x)=y 를 구해보자. 2차 함수를 구하기 위해서는 이 함수가 지나는 세 점을 알아야 한다. 폰트 크기 차에 상관없이 완전한 흰색#fff의 폰트는 항상 같은 흰색#fff과 쌍을 이루므로 이 함수는 (256, 256)을 지날 것이다. 이 함수의 x절편은 작은 크기의 폰트가 #000일 때 쌍을 이루는 색상 값이며 즉 상수 c 이다. 나머지 한 점은 0부터 265의 중앙값인 128을 지나는 색상 쌍으로 잡아보았다. 이를 t라고 하면 구하고자 하는 함수는 세 점 (0, c), (128, t), (256, 256)을 지난다.

이 계산을 처음 할 땐 c와 t 값에 눈으로 보기에 적절해 보이는 수를 집어넣었는데, 그러자 f3(x)=y 즈음 되니 오차의 폭이 꽤 커졌다. 그래서 c와 t를 임의의 수로 두고 아래처럼 계수를 구하는 식을 세웠다.

  • f1(x) = ax2 + bx + c
  • b = (4t - 3c)/256 - 1
  • a = (t - c - 128b)/1282

위 두 식에 c와 t를 조정하며 대입해보면서 f3(0)이 50에서 크게 벗어나지 않는 값을 찾았다. 그렇게 얻은 c는 19, t는 134였다. 그리하여 (0, 19), (128, 134), (256, 256) 세 점을 지나는 f1(x)는 다음과 같이 구해졌다.

  • f1(x) = 0.000213623x2 + 0.87109375x + 19 = y

이즈음 돼서 소회를 풀어보자면, 내가 수학 비스름한 것을 가까이하던 시기는 고3에서 끝이 났는데 고교 과정에서는 소수점 아홉째 자리까지 연산을 한다면 그건 뭔가 잘못됐다는 뜻이다. 그래서 나는 이 식을 제대로 구하기 전까지 눈대중어림짐작으로 반올림해서 쉽고 깔끔한 식을 얻고자 했으나 모두 실패하고 결국 어떤 수도 버리지 않고 계산해서야 위 식을 얻을 수 있었다. 그렇다. 읽는데 10분도 채 걸리지 않는 이 글을 쓰려고 나는 3주 가까이 소비했다.그러니 숫자의 괴기함에 놀라지 않기를 바란다.

다시 본론으로 돌아가서 앞서 쓴 대로 fn(fn(x))하는 방식으로 f2(x), f3(x)…를 차례로 구해보았다.

  • f2(x) = 0.0003815657x2 + 0.7631477118x + 35.6278991699
  • f3(x) = 0.000513941x2 + 0.6719217199x + 50.3064021088
  • f4(x) = 0.00061831x2 + 0.5942039783x + 63.3622155898
  • f5(x) = 0.0007004136x2 + 0.5275219477x + 75.0520774642
  • f6(x) = 0.0007646696x2 + 0.4699449895x + 85.5806945636
  • f7(x) = 0.0008145185x2 + 0.4199465565x + 95.1133951598
  • f8(x) = 0.0008526675x2 + 0.3763060287x + 103.7852373356
  • f9(x) = 0.0008812668x2 + 0.3380375466x + 111.7076856363
  • f10(x) = 0.0009020384x2 + 0.3043375988x + 118.9735848393

이들을 그래프로 그리면 아래와 같다. (이미지의 가장 진한 그래프는 x=y이다)

이미지 10. f1(x), f2(x) … f10(x)까지의 그래프

방정식은 불안한 모양새지만 그래프는 꽤 그럴듯하다. 이제 이 그래프가 올바른 색상 쌍들로 이루어져 있는지 테스트해보았다.

이미지 11-1. 기준 폰트 색상이 #000일 때 12px부터 24px까지의 색상 쌍
이미지 11-2. 기준 폰트 색상이 #444일 때 12px부터 24px까지의 색상 쌍
이미지 11-3. 기준 폰트 색상이 #888일 때 12px부터 24px까지의 색상 쌍
이미지 11-4. 기준 폰트 색상이 #ccc일 때 12px부터 24px까지의 색상 쌍

글자 크기에 따라 획의 밀도가 달라져서 작은 글씨와 큰 글씨를 비교해 보면 작은 글씨가 좀 더 진해 보이는 경향이 있지만, 전체적으로 봤을 때 글씨가 커질수록 앞으로 튀어나오거나 뒤로 사라지는 느낌 없이 같은 평면 위에 있는 인상이다. (위 이미지를 모바일이나 너비가 좁은 브라우저로 본다면 작은 글씨가 월등히 진하게 보일 것이다. 이는 이미지가 축소되면서 픽셀이 어그러졌기 때문이다.)

같은 방식으로 어떤 종류의 폰트든지 npx 큰 폰트와 비교했을 때 (0, c), (128, t) 값을 뽑을 수 있다면 fn(x) = (t - c - 128b)/1282x2+{(4t - 3c)/256 - 1}x + c 에 대입해 n px 차이 나는 폰트와 굵기가 같아 보이는 색상 쌍을 구해낼 수 있다.

결론

  1. 폰트의 자족은 한정되어있다.
  2. 그러므로 크기가 근소하게 다른 두 폰트의 획 굵기는 같기 어렵다.
  3. 그러나 폰트의 색이 밝으면 같은 굵기임에도 더 얇아 보이는 성질을 이용해, 크기가 다른 두 폰트의 굵기를 같아 보이게 할 수 있다.
  4. 크기가 작은 폰트가 각각 #000, #808080일 때 크기가 큰 폰트의 굵기가 같아 보이는 색상 짝 c, t를 구한다.
  5. 그 후 c, t를 다음 식에 대입한다.
    • fn(x) = (t - c - 128b)/1282x2 + {(4t - 3c)/256 - 1}x + c = y
  1. 이 포스트의 모든 이미지에 사용된 폰트는 Apple SD Gothic Neo다.

  2. Pixel Precision을 다루는 대표적인 Guide는 Ustwo에서 정리한 PIXEL PERFECT PRECISION HANDBOOK 3가 있다.

  3. 모든 소수는 3자리 수에서 반올림했다.

  4. 이 실험은 무채색만을 대상으로 진행했다. 또한, 개개인마다 시력과 모니터의 색공간이 다르므로 결론에 이견이 있을 수 있다.

  5. 단, 폰트의 크기가 너무 커서 글씨의 획이 선이 아닌 면으로 느껴지면 색상이 획 굵기에 미치는 영향이 현저히 줄어든다. 위 포스팅에선 이렇게 큰 폰트는 다루지 않았다.