[JB]
2026.04.12기술

디자인 시스템에서 fluid typography 도입하기

이 글은 clamp() 기반 폰트 스케일을 토큰화하여 모바일/데스크톱 분기를 줄이고 일관성을 유지한 경험을 정리한 것이다.

왜 fluid typography 인가

전통적인 반응형 타이포는 breakpoint마다 font-size를 재정의했다. 단점이 명확하다.

  • 분기 사이에서 글자 크기가 점프
  • 새 breakpoint가 생기면 모든 토큰을 재배치
  • CSS LOC가 빠르게 늘어남

"Fluid typography는 단순히 글자 크기가 부드럽게 변하는 것 이상이다. 디자이너와 엔지니어가 공유 가능한 단일 척도다."

clamp 토큰 설계

아래 슬라이더로 viewport 폭을 조정해 보면 clamp() 가 어떤 곡선을 그리는지 직관적으로 잡힌다.

Fluid Typography

clamp(1rem, 0.8vw + 0.7rem, 1.6rem)

viewport800px
= 17.6pxAa 한글 abc 123

다음과 같은 스케일을 도입했다.

const fontSize = {
  100: "clamp(0.7rem, 0.24vw + 0.6rem, 0.8rem)",
  200: "clamp(0.8rem, 0.64vw + 0.68rem, 1.2rem)",
  300: "clamp(1rem, 0.8vw + 0.8rem, 1.4rem)",
  400: "clamp(1.375rem, 1vw + 1.125rem, 1.625rem)",
  500: "clamp(1.2rem, 1.2vw + 1rem, 2rem)",
  600: "clamp(1.6rem, 2vw + 1.2rem, 2.8rem)",
} as const;

스케일 단계 의미

steprangerole
10011~13pxcaption
20013~19pxbody
30016~22pxlead
40022~26pxsubtitle
50019~32pxheading
60026~45pxdisplay

의사 결정 흐름

flowchart TD A[breakpoint별 font-size 재정의] --> B{유지보수 부담} B -- 크다 --> C[fluid clamp 도입] B -- 작다 --> A C --> D[step 기반 토큰화] D --> E[component에서 role 참조]

사용 예

import { primitives } from "notepad-ds/tokens/primitives";
 
const heading = style({
  fontSize: primitives.font.role.heading,
});

마무리

fluid는 만능이 아니다. 매우 작은 화면(320px 이하)이나 매우 큰 화면(2560px 이상)에선 clamp의 min/max가 직접 한계를 만들어 추가 조정이 필요할 수 있다. 하지만 일반적인 viewport 범위에서는 breakpoint를 거의 제거할 수 있어 코드 자체가 단순해진다.