04 — Variable Fonts

정적 폰트 9개를 보내는 대신, 가변 축을 가진 폰트 1개를 보낸다. Variable font는 디자인 공간을 코드로 보간하는 폰트 기술이다.


한 문장 답 (Pyramid Top)

Variable font는 하나의 폰트 파일이 N차원 축을 가지고, CSS가 font-variation-settings로 그 축의 임의 위치를 지정하면 폰트 엔진이 실시간으로 보간해 글자를 그리는 기술이다. 정적 폰트 9개 (Thin..Black) = 약 250KB × 9 = 2.25MB, Variable 폰트 1개 = 약 350KB — 거의 6.4배 압축되면서도 200, 250, 333 같은 비표준 weight까지 표현 가능하다.


Why — 왜 등장했나

1) 정적 폰트의 곱셈 비용

전통적으로 한 폰트의 전체 weight·style은 별도 파일이었다:

Inter-Thin.woff2          (250KB)
Inter-ExtraLight.woff2    (250KB)
Inter-Light.woff2         (250KB)
Inter-Regular.woff2       (250KB)
Inter-Medium.woff2        (250KB)
Inter-SemiBold.woff2      (250KB)
Inter-Bold.woff2          (250KB)
Inter-ExtraBold.woff2     (250KB)
Inter-Black.woff2         (250KB)
+ 9 italic 버전
= 18 파일, 4.5MB

대부분 사이트가 2-3 weight만 쓰면서도 디자이너가 “오늘은 600이 필요” 라며 weight를 추가하면 250KB 다운로드 추가.

2) 디자인 공간의 연속성

폰트 디자이너는 사실 100, 200, ..., 900 같은 9개 이 아니라 연속적인 디자인 공간을 만든다. 9개는 대표 스냅샷일 뿐. Variable font는 이 연속 공간 전체를 한 파일에 담는다.

3) 모바일 시대의 대역폭 제약

LTE/3G에서 4MB 폰트는 5-10초 다운로드. Variable font는 250-500KB로 같은 표현력 → 자원 1/9.


How — Variable font의 5개 표준 축

OpenType은 5개의 등록된 축 을 정의한다 — 모든 variable font가 따르는 표준 이름.

CSS 속성의미일반 범위
wghtfont-weightweight (굵기)100..900
wdthfont-stretchwidth (폭)50..200%
slntfont-style: obliqueslant (기울기, 각도)-14..14deg
italfont-style: italicitalic (이탤릭 켜기)0 또는 1
opszfont-optical-sizingoptical size (시각 크기)8..144

추가로 폰트 제작자가 커스텀 축을 정의할 수 있다 (GRAD, MONO, XOPQ 등 — 4글자 대문자).


How — CSS로 축 제어하는 두 가지 방법

1) High-level 속성 (권장)

.heading {
  font-family: "Inter";
  font-weight: 650;          /* wght 축 */
  font-stretch: 110%;        /* wdth 축 */
  font-style: italic;        /* ital 축 */
  font-optical-sizing: auto; /* opsz 축 — font-size에 자동 매핑 */
}
  • 브라우저가 해당하는 variation 축에 자동 매핑.
  • font-weight: 650 같은 비표준 정수 값도 가능.
  • font-optical-sizing: autofont-size에 따라 opsz를 자동 조정 (작은 크기엔 두꺼운 stroke, 큰 크기엔 얇은 stroke).

2) Low-level font-variation-settings

.heading {
  font-family: "Inter";
  font-variation-settings:
    "wght" 650,
    "wdth" 110,
    "slnt" -8,
    "GRAD" 50;  /* 커스텀 축 */
}
  • 커스텀 축을 쓰려면 반드시 이 속성.
  • 주의: font-variation-settings이전 값을 모두 덮어쓴다 — 한 축만 바꾸려고 해도 모든 축을 다시 적어야 함.

3) 두 방식 혼용 시 충돌

.a {
  font-weight: 700;
  font-variation-settings: "wght" 400;  /* 700? 400? */
}

font-variation-settings가 이긴다 (low-level이 high-level을 덮어씀). 따라서 일반적인 weight 변경은 font-weight로, 커스텀 축은 font-variation-settings로.


How — @font-face 등록

@font-face {
  font-family: "Inter";
  src: url("/fonts/InterVariable.woff2") format("woff2-variations");
  font-weight: 100 900;         /* wght 축 범위 */
  font-stretch: 75% 125%;       /* wdth 축 범위 */
  font-style: oblique -14deg 0deg;  /* slnt 축 범위 (italic만 0deg) */
  font-display: swap;
}
  • weight·stretch·style 모두 범위 (2개 값) 로 명시.
  • format: "woff2-variations" (구) 또는 "woff2" tech("variations") (CSS Fonts Level 4).

Italic이 별도 파일인 경우

@font-face {
  font-family: "Inter";
  src: url("/fonts/InterVariable.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
}
@font-face {
  font-family: "Inter";
  src: url("/fonts/InterVariable-Italic.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: italic;
}

브라우저는 font-style: italic이 등장하면 두 번째 파일을 받는다.


What — 파일 크기 비교

폰트정적 (9 weight × 2 style)Variable절감
Inter (Latin)약 2.25MB약 350KB84%
Roboto Flex약 3MB약 1.5MB (축 12개)50%
Pretendard (Latin+Korean)약 27MB (3MB × 9)약 2.4MB91%
Recursive약 2.8MB약 500KB (5축)82%

한글 폰트일수록 variable의 이득이 크다 — 글리프 수가 많아 정적 폰트의 곱셈 비용이 커지기 때문.


What — 흥미로운 축 활용

1) opsz (Optical Sizing) — 자동

:root { font-optical-sizing: auto; }
h1 { font-size: 48px; }   /* opsz 48 — 세련된 얇은 획 */
p  { font-size: 14px; }   /* opsz 14 — 가독성 위해 두꺼운 stroke */

폰트 디자이너가 크기별로 다른 글자 모양을 디자인해 둔다 (Roboto Serif, Source Serif Pro 등). autofont-size에 자동 매핑.

2) wght로 hover 애니메이션

.button {
  font-family: "Inter";
  font-weight: 400;
  transition: font-weight 200ms;
}
.button:hover {
  font-weight: 600;
}
  • 정적 폰트로는 깜빡 바뀐다 (400.woff2 → 600.woff2 스왑).
  • Variable font는 부드럽게 두꺼워진다 — 폰트 엔진이 보간.

3) slnt로 미세 기울임

em {
  font-style: oblique -8deg;  /* 8도만 기울임 — 진짜 italic이 아니라 oblique */
}
  • 정적 italic은 0 or 1.
  • Variable의 slnt0~14도 사이 어디든.

4) Recursive의 MONO

code {
  font-family: "Recursive";
  font-variation-settings: "MONO" 1;  /* 0 = 프로포셔널, 1 = 모노스페이스 */
}
  • 한 폰트가 프로포셔널 ↔ 모노 사이를 연속.
  • MONO 0.5 같은 반-모노 도 가능.

What — font-variation-settings 변수와 합치기

:root {
  --font-weight: 400;
  --font-width: 100;
}
 
body {
  font-variation-settings: "wght" var(--font-weight), "wdth" var(--font-width);
}
 
.heading {
  --font-weight: 700;
  --font-width: 110;
}
  • 디자인 시스템에서 축 값을 토큰화.
  • @property로 타입 선언하면 애니메이션도 가능:
@property --font-weight {
  syntax: "<number>";
  initial-value: 400;
  inherits: true;
}
 
.morph {
  transition: --font-weight 300ms;
}
.morph:hover {
  --font-weight: 700;
}

What-if — 잘못 쓰면

1) font-variation-settings의 덮어쓰기 함정

.heading {
  font-variation-settings: "wght" 700;
}
.heading.italic {
  font-variation-settings: "slnt" -10;  /* wght이 사라진다! */
}

slnt만 설정하면서 wght이 기본값으로 리셋된다. 항상 모든 축을 다시 적거나, 변수로 합성:

.heading {
  --w: 700;
  --s: 0;
  font-variation-settings: "wght" var(--w), "slnt" var(--s);
}
.heading.italic { --s: -10; }

2) 정적 + variable 혼용 with 같은 family

@font-face { font-family: "Inter"; src: url("inter-var.woff2") ...; font-weight: 100 900; }
@font-face { font-family: "Inter"; src: url("inter-bold.woff2"); font-weight: 700; }
/* font-weight: 700 시 브라우저가 어느 파일을 쓸지 불명확 */

→ Variable이 있으면 정적은 모두 제거.

3) 브라우저 미지원 fallback 없음

@font-face {
  font-family: "Inter";
  src: url("/inter-var.woff2") format("woff2-variations");
  /* 구식 브라우저는 못 읽음 */
}

→ 2024년 기준 IE만 미지원 (woff2-variations). IE 지원 필요하면 정적 fallback:

@font-face {
  font-family: "Inter";
  src: url("/inter-var.woff2") format("woff2-variations"),
       url("/inter-regular.woff2") format("woff2");
}

4) 모든 축을 변동 가능하게

.text {
  transition: font-variation-settings 300ms;  /* 모든 축이 동시에 변동 */
}

→ 한 축만 변동하고 싶을 땐 --var + transition: --var축 단위 제어.


Insight — 흥미로운 이야기

“Variable Font는 1990년대 Adobe Multiple Master의 부활”

1991년 Adobe는 Multiple Master 폰트 기술을 발표했다 — 여러 master 디자인 사이를 보간하는 변형 폰트. 디자인적으로는 혁신이었지만 너무 빨랐다 — OS 지원 부족, 디자이너의 학습 곡선, 인쇄 워크플로 부재로 1999년 Adobe가 단종. 18년이 지난 2016년 ATypI 컨퍼런스에서 Adobe·Apple·Google·Microsoft 4사가 OpenType 1.8 + Variable Font를 공동 발표 — Multiple Master의 부활이었다. 이번엔 이라는 사용처가 있었고, 대역폭 압박이라는 필요성이 있었다. 기술이 시대를 30년 앞서면 죽고, 시대가 따라잡으면 부활한다.

“Inter는 variable font 시대의 첫 성공”

2016년 스웨덴의 Rasmus Andersson(전 Spotify·Figma)이 Figma UI 폰트로 쓰려고 Inter를 디자인했다. 2018년 Inter v3에서 variable 버전 (InterVariable.woff2) 을 추가 — 약 350KB로 100..900 weight 전체. Figma·Linear·Vercel·GitHub Primer가 채택했고, 2024년 모든 모던 SaaS 디자인 시스템의 기본 폰트가 됐다. Inter Display 라는 별도 display-size 최적화 variant도 있는데, 이건 opsz 축의 정적 export. 한 사람의 디자이너가 만든 폰트가 변하는 폰트의 시대를 열었다.


요약 + Mermaid

  • Variable font는 한 파일이 N차원 축을 가짐 — wght/wdth/slnt/ital/opsz + 커스텀.
  • 정적 9개 weight = ~2.25MB, Variable = ~350KB → 6-9배 압축, 비표준 weight도 표현 가능.
  • High-level font-weight/font-stretch 또는 low-level font-variation-settings.
  • font-variation-settings이전 값을 덮어씀 → 변수로 축 분리해서 합성.
  • font-optical-sizing: auto로 크기별 글자 모양 자동 전환.

다음 문서 → 05-text-properties: 글자가 정해진 다음 — 텍스트가 어떻게 흐르는가.