글자 크기를 화면마다 눈대중으로 정하면 제목이 여기선 22px, 저기선 21px처럼 미묘하게 어긋납니다. 타이포 시스템은 쓸 수 있는 크기와 굵기를 사다리로 미리 정해 두고 그 칸만 골라 쓰게 만듭니다. 아래 코드는 타입 스케일을 토큰으로 세우고 clamp로 반응형까지 입히는 흐름입니다.

37.1 px를 흩뿌리는 나쁜 예

가장 흔한 출발점은 요소마다 그때그때 px를 박는 방식입니다. 언뜻 자유로워 보이지만 크기가 제각각으로 불어납니다.


.page-title { font-size: 29px; }
.card-title { font-size: 21px; }
.section-title { font-size: 22px; }
.body { font-size: 15px; }
.caption { font-size: 13px; }
.note { font-size: 12px; }


21px와 22px는 왜 다른지 아무도 설명하지 못합니다. 이런 값들은 손볼 때마다 근거 없이 늘어나고, 화면 사이의 통일감을 갉아먹습니다.

37.2 스케일을 토큰으로 세우기

크기를 몇 단계로 못 박고 이름을 붙입니다. 한 칸에서 다음 칸으로 약 1.2배씩 커지는 모듈러 스케일이라 어떤 두 크기를 나란히 놓아도 리듬이 맞습니다.


:root {
--font-size-xs: 0.75rem; /* 12px */
--font-size-sm: 0.875rem; /* 14px */
--font-size-base: 1rem; /* 16px */
--font-size-lg: 1.25rem; /* 20px */
--font-size-xl: 1.5rem; /* 24px */
--font-size-2xl: 1.875rem; /* 30px */
}


rem으로 잡아 두면 사용자가 브라우저 기본 글자 크기를 키웠을 때 스케일 전체가 함께 늘어납니다. px로 못 박으면 그 배려가 사라집니다.

37.3 굵기, 행간, 서체 토큰

크기만 사다리로 잡을 게 아니라 굵기와 행간, 서체도 토큰으로 묶습니다. 굵기는 서너 단계면 위계를 만들기에 충분합니다.


:root {
--font-family-base: system-ui, "Segoe UI", sans-serif;
--font-weight-normal: 400;
--font-weight-medium: 500;
--font-weight-bold: 700;
--line-height-tight: 1.25;
--line-height-normal: 1.6;
}
body {
font-family: var(--font-family-base);
font-size: var(--font-size-base);
line-height: var(--line-height-normal);
font-weight: var(--font-weight-normal);
}


제목처럼 큰 글자는 tight한 행간이 어울리고 본문은 넉넉한 1.6이 읽기 편합니다. 한글은 네모반듯해 빽빽해 보이니 본문 행간을 조금 여유롭게 잡았습니다.

37.4 유틸리티 클래스로 묶어 쓰기

크기와 굵기와 행간을 한 벌로 묶은 유틸리티를 만들면, 글자를 놓을 때 값을 세 개 적는 대신 이름 하나만 부르면 됩니다.


.text-heading {
font-size: var(--font-size-2xl);
font-weight: var(--font-weight-bold);
line-height: var(--line-height-tight);
}
.text-subhead {
font-size: var(--font-size-lg);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-tight);
}
.text-body {
font-size: var(--font-size-base);
line-height: var(--line-height-normal);
}
.text-caption {
font-size: var(--font-size-sm);
color: #6b7280;
}


본문 크기를 한 단계 키우고 싶으면 --font-size-base 값만 바꾸면 됩니다. text-body라는 이름에 기대던 모든 글자가 한꺼번에 따라 커집니다.

37.5 h1부터 h6까지 매핑

시맨틱 태그에도 같은 스케일을 연결해 두면 마크업만 해도 위계가 서게 됩니다. 유틸리티를 붙이지 않아도 기본 모습이 반듯합니다.


h1 {
font-size: var(--font-size-2xl);
font-weight: var(--font-weight-bold);
line-height: var(--line-height-tight);
}
h2 {
font-size: var(--font-size-xl);
font-weight: var(--font-weight-bold);
}
h3 {
font-size: var(--font-size-lg);
font-weight: var(--font-weight-medium);
}
small {
font-size: var(--font-size-xs);
}


제목 태그가 저마다 정해진 칸을 밟으니, 글쓴이가 크기를 고민하지 않아도 문서 구조 그대로 시각적 위계가 따라옵니다.

37.6 clamp로 반응형 타이포

넓은 화면에서 시원하던 큰 제목이 좁은 화면에선 몇 글자 만에 줄이 넘어갑니다. clamp로 화면 폭에 따라 크기가 부드럽게 줄어들게 합니다.


:root {
--font-size-2xl: clamp(1.5rem, 4vw, 1.875rem);
--font-size-xl: clamp(1.25rem, 3vw, 1.5rem);
}
.hero-title {
font-size: var(--font-size-2xl);
font-weight: var(--font-weight-bold);
line-height: var(--line-height-tight);
}


clamp의 가운데 값 4vw가 화면 폭을 따라 크기를 밀고 당기고, 양쪽 1.5rem과 1.875rem이 너무 작아지거나 커지지 않게 잡아 줍니다. 미디어쿼리를 여러 개 쓰지 않고 한 줄로 반응형이 끝납니다.

37.7 본문은 지키고 폭은 제한

큰 제목은 좁은 화면에서 겸손해져도 되지만 오래 읽는 본문은 함부로 줄이면 안 됩니다. 한 줄 길이도 너무 길면 다음 줄을 찾기 힘들어 제한합니다.


.prose {
font-size: var(--font-size-base);
line-height: var(--line-height-normal);
max-width: 65ch;
}
.prose p + p {
margin-top: 1em;
}


ch 단위는 글자 폭을 기준으로 하니 65ch면 한 줄에 65자 안팎으로 담깁니다. 넓은 화면이라고 글을 끝까지 늘어놓지 않고 읽기 편한 폭 안에 가둔 것입니다.

37.8 정리

타이포 시스템은 크기와 굵기와 행간을 사다리로 세우고, 유틸리티와 태그에 그 칸을 연결하고, clamp로 화면 폭에 맞춰 유연하게 다루는 일입니다. px를 흩뿌리던 화면이 스케일 토큰 위에 올라서면, 본문 크기 한 줄만 바꿔도 제품 전체의 글자가 함께 숨을 고릅니다. 글자를 값이 아니라 역할로 부르는 습관이 그 출발점입니다.