이 글은 누구를 위한 것인가
- 모바일과 데스크탑에서 폰트 크기를 따로 관리하는 게 번거로운 디자이너·개발자
- 가변 폰트(Variable Font)가 무엇인지 궁금한 분
- 디자인 시스템에 타이포그래피 토큰을 도입하려는 팀
들어가며
타이포그래피는 디자인의 80%다. 잘 설계된 타입 시스템 하나가 UI 전체를 일관되게 만들어준다. 그런데 많은 팀에서 타이포그래피는 가장 체계 없이 관리되는 영역이기도 하다.
모바일에서는 font-size: 14px, 태블릿에서는 font-size: 16px, 데스크탑에서는 font-size: 18px — 미디어 쿼리마다 다른 값을 하드코딩한다. 화면 크기가 달라질 때마다 폰트가 뚝뚝 끊기며 변한다.
더 좋은 방법이 있다. **유동 타이포그래피(Fluid Typography)**다. 화면 크기에 따라 폰트가 자연스럽게 흘러가듯 변하는 방식이다. 그리고 **가변 폰트(Variable Font)**를 더하면 파일 하나로 굵기, 너비, 기울기를 CSS에서 자유롭게 조절할 수 있다.
1. 기존 타이포그래피 설계의 한계
문제 1: 브레이크포인트에서 폰트가 점프한다
미디어 쿼리 기반 타이포그래피는 특정 너비에서 폰트가 갑자기 커진다.
/* 기존 방식 */
h1 { font-size: 24px; }
@media (min-width: 768px) {
h1 { font-size: 36px; } /* 768px에서 갑자기 36px로 점프 */
}
@media (min-width: 1280px) {
h1 { font-size: 48px; } /* 1280px에서 또 48px로 점프 */
}
브레이크포인트 직전/직후 화면 크기에서 폰트가 부자연스럽게 변한다.
문제 2: 너무 많은 값을 관리해야 한다
컴포넌트마다 3개 이상의 브레이크포인트, 헤딩 6개 레벨, 본문/캡션/레이블 등을 관리하면 수십 개의 폰트 크기 값이 생긴다.
2. CSS clamp()로 유동 타이포그래피 만들기
CSS clamp() 함수가 이 문제를 해결한다. 최솟값, 유동값, 최댓값 세 가지를 한 번에 정의한다.
h1 {
font-size: clamp(24px, 4vw, 48px);
/* ↑최소 ↑유동 ↑최대 */
}
이렇게 하면:
- 화면이 아무리 작아도 24px 아래로는 내려가지 않음
- 화면이 커질수록 4vw 비율로 자연스럽게 커짐
- 아무리 커도 48px를 넘지 않음
폰트가 미디어 쿼리 브레이크포인트에서 뚝 끊기지 않고, 화면 크기에 따라 부드럽게 변한다.
clamp() 값 계산하기
유동값 계산이 가장 어렵다. 수학적으로 계산할 수도 있지만, utopia.fyi 같은 도구를 사용하면 최소/최대 화면 크기와 폰트 크기를 입력하면 자동으로 clamp() 값을 계산해준다.
/* utopia.fyi로 생성한 유동 타이포그래피 스케일 */
--step-0: clamp(1rem, 0.96rem + 0.22vw, 1.13rem);
--step-1: clamp(1.13rem, 1.04rem + 0.43vw, 1.41rem);
--step-2: clamp(1.27rem, 1.12rem + 0.73vw, 1.76rem);
--step-3: clamp(1.42rem, 1.2rem + 1.12vw, 2.2rem);
--step-4: clamp(1.6rem, 1.28rem + 1.62vw, 2.75rem);
--step-5: clamp(1.8rem, 1.35rem + 2.25vw, 3.43rem);
3. 타이포그래피 스케일 시스템 설계
폰트 크기를 무작위로 정하지 않고, 음악적 비율을 기반으로 체계적인 스케일을 만든다.
주요 스케일 비율
| 스케일 이름 | 비율 | 특성 |
|---|---|---|
| Minor Second | 1.067 | 차이가 미묘, 대형 텍스트 시스템에 적합 |
| Major Second | 1.125 | 균형 잡힌 차이, 가장 많이 사용 |
| Minor Third | 1.2 | 명확한 계층, 일반 웹에 적합 |
| Perfect Fourth | 1.333 | 강한 계층, 콘텐츠 중심 사이트 |
| Major Third | 1.25 | Minor Third와 Perfect Fourth 사이 |
[Perfect Fourth 스케일 예시 - 기준: 16px]
xs: 9px (16 ÷ 1.333 ÷ 1.333)
sm: 12px (16 ÷ 1.333)
base: 16px (기준)
lg: 21px (16 × 1.333)
xl: 28px (16 × 1.333²)
2xl: 37px (16 × 1.333³)
3xl: 50px (16 × 1.333⁴)
모든 폰트 크기가 수학적 비율로 연결되면 전체 타이포그래피가 자연스럽게 조화롭게 느껴진다.
4. 가변 폰트(Variable Font)의 원리
기존 폰트는 굵기마다 별도 파일이 필요했다.
기존 방식:
Pretendard-Thin.woff2 (100)
Pretendard-Light.woff2 (300)
Pretendard-Regular.woff2 (400)
Pretendard-Medium.woff2 (500)
Pretendard-SemiBold.woff2 (600)
Pretendard-Bold.woff2 (700)
Pretendard-ExtraBold.woff2 (800)
→ 7개 파일, 각각 100~200KB = 합계 1MB 이상
가변 폰트는 모든 굵기 정보가 하나의 파일 안에 담겨 있다.
가변 폰트:
Pretendard-Variable.woff2 → 단 하나의 파일, 약 300KB
→ CSS에서 1에서 999까지 모든 굵기 자유롭게 사용 가능
/* 가변 폰트 사용 */
@font-face {
font-family: 'Pretendard Variable';
src: url('PretendardVariable.woff2') format('woff2-variations');
font-weight: 100 900; /* 지원 범위 */
}
/* 정수 굵기만이 아닌 모든 굵기 사용 가능 */
.heading { font-weight: 650; } /* 650이라는 굵기! 기존 폰트 불가 */
.caption { font-weight: 375; }
5. 한국어 가변 폰트 현황
한국어는 글자 수가 많아 폰트 파일이 영어보다 훨씬 크다. 가변 폰트 지원도 늦게 시작됐지만, 이제 좋은 선택지가 있다.
| 폰트 | 무게 범위 | 특징 | 라이선스 |
|---|---|---|---|
| Pretendard Variable | 100~900 | 가장 널리 사용, 모던 산세리프 | SIL OFL (무료) |
| Noto Sans KR (Variable) | 100~900 | Google Fonts, 다국어 지원 탁월 | SIL OFL (무료) |
| SUIT Variable | 100~900 | Pretendard와 유사, 가독성 우수 | SIL OFL (무료) |
Pretendard Variable은 현재 국내 웹 서비스에서 가장 많이 사용되는 가변 폰트다. 카카오, 토스, 당근마켓 등에서 적용 중이다.
6. 다국어 서비스에서 타이포그래피 통일하기
한국어/영어/일본어가 혼용되는 서비스에서 타이포그래피를 일관되게 관리하는 것은 까다롭다. 각 언어의 폰트 높이(Cap Height)와 기준선(Baseline)이 다르기 때문이다.
실용적인 전략
/* 언어별 폰트 스택 정의 */
:root {
--font-sans-ko: 'Pretendard Variable', sans-serif;
--font-sans-en: 'Inter Variable', sans-serif;
--font-sans-ja: 'Noto Sans JP Variable', sans-serif;
}
/* 언어 속성으로 자동 적용 */
:lang(ko) { font-family: var(--font-sans-ko); }
:lang(en) { font-family: var(--font-sans-en); }
:lang(ja) { font-family: var(--font-sans-ja); }
/* 폰트 크기는 공통 토큰 사용 */
h1 { font-size: var(--step-4); }
폰트 종류는 다르지만, 크기 스케일은 공통 토큰으로 통일한다. 이렇게 하면 한국어 영역과 영어 영역의 제목 크기가 동일한 시각적 비중을 갖게 된다.
7. Figma에서 타이포그래피 토큰으로 관리하기
설계한 타이포그래피 스케일을 Figma에서 Variables로 관리하면, 디자이너와 개발자가 같은 값을 참조하게 된다.
Figma Variables 구조:
Typography/
Scale/
step-0: 16px
step-1: 21px
step-2: 28px
...
Semantic/
heading-xl: {step-4}
heading-lg: {step-3}
body-base: {step-0}
caption: {step--1}
Weight/
regular: 400
medium: 500
bold: 700
이 구조를 코드의 CSS 변수와 동기화하면, Figma에서 heading-xl을 쓴 텍스트가 코드에서도 동일한 크기로 자동으로 나온다.
맺으며
유동 타이포그래피는 한번 설정해두면 이후 반응형 작업이 크게 줄어드는 투자다. 미디어 쿼리마다 폰트 크기를 따로 정의하는 대신, clamp() 하나로 모든 화면을 커버한다.
가변 폰트는 파일 크기를 줄이고 더 세밀한 굵기 표현을 가능하게 한다. Pretendard Variable 하나만 불러와도 7개 굵기를 모두 쓸 수 있다.
이 두 가지를 디자인 토큰 시스템과 결합하면, 타이포그래피가 디자인 시스템의 가장 강력한 무기가 된다. 어디서 보든 일관되고, 어떤 화면에서든 아름답게 작동하는 타이포그래피.