콘텐츠로 이동
Study Noteshadcn/ui

6. 글자 리소스

화면의 대부분은 색도 버튼도 아니고 글자다. 그런데 토큰 관리에서 가장 자주 빠진다.

이 장에서 처음 나오는 말5개
폰트 패밀리Font Family
어떤 글꼴을 쓸 것인가. --font-sans, --font-mono 처럼 역할로 이름 붙인다.
줄 간격Line Height
줄과 줄 사이 간격. 글자 크기의 몇 배로 지정한다. 한글은 영문보다 넉넉해야 읽힌다.
자간Letter Spacing
글자 사이 간격. 영문 큰 제목은 좁히면 좋아지지만 한글은 좁히면 뭉개진다.
폴백Fallback
지정한 폰트가 없을 때 대신 쓸 폰트 목록. 순서대로 시도한다.
시스템 폰트System Font Stack
사용자 기기에 이미 있는 기본 글꼴. 내려받을 게 없어 가장 빠르다.

폰트 패밀리 — 역할로 이름 붙인다

섹션 제목: “폰트 패밀리 — 역할로 이름 붙인다”

폰트도 색과 똑같다. “Pretendard”가 아니라 “본문용 글꼴”이라고 이름 붙인다.

@theme inline {
--font-sans: 'Pretendard Variable', ui-sans-serif, system-ui, sans-serif;
--font-mono: ui-monospace, 'SFMono-Regular', Menlo, monospace;
}
<p className="font-sans">본문</p>
<code className="font-mono">코드</code>

폰트를 바꾸려면 한 줄만 고친다. 컴포넌트는 font-sans밖에 모른다.

토큰역할빈도
--font-sans본문·UI 전체★★★
--font-mono코드, 숫자 정렬이 필요한 표★★☆
--font-serif제목에 개성이 필요할 때★☆☆

대부분의 앱은 --font-sans 하나로 끝난다. 폰트를 여러 개 섞는 건 대체로 나쁜 신호다.

--font-sans: 'Pretendard Variable', ui-sans-serif, system-ui, sans-serif;
/* ① ② ③ ④ */
  • ① 원하는 폰트. 아직 안 내려받았거나 실패하면 →
  • ②③ 기기 기본 글꼴 (iOS는 SF Pro, Windows는 Segoe UI, Android는 Roboto)
  • ④ 최후의 보루

폴백이 없으면 폰트 로딩 실패 시 Times New Roman이 나온다. 화면이 순식간에 90년대가 된다.

간격과 같은 원리다. 아무 크기나 쓰지 않고 정해진 단계만 쓴다.

text-xs다람쥐 헌 쳇바퀴 Ag12px / 16px
text-sm다람쥐 헌 쳇바퀴 Ag14px / 20px
text-base다람쥐 헌 쳇바퀴 Ag16px / 24px
text-lg다람쥐 헌 쳇바퀴 Ag18px / 28px
text-xl다람쥐 헌 쳇바퀴 Ag20px / 28px
text-2xl다람쥐 헌 쳇바퀴 Ag24px / 32px
text-3xl다람쥐 헌 쳇바퀴 Ag30px / 36px
text-4xl다람쥐 헌 쳇바퀴 Ag36px / 40px

Tailwind는 크기와 줄 간격을 한 쌍으로 준다. text-sm은 14px 글자 + 20px 줄 간격이다. 크기만 바꾸면 줄 간격이 안 따라와서 어색해지기 때문이다.

클래스크기어디에
text-xs12px배지, 캡션, 표의 부가정보
text-sm14pxUI 기본 — 버튼, 라벨, 입력창. shadcn/ui 대부분이 이것
text-base16px본문 문단
text-lg ~ text-xl18~20px카드 제목, 섹션 제목
text-2xl ~ text-4xl24~36px페이지 제목, 히어로

제목 계층은 크기 차이가 명확히 보여야 한다.

<h1 className="text-3xl">페이지 제목</h1>
<h2 className="text-xl">섹션 제목</h2>
<h3 className="text-base font-semibold">소제목</h3>

text-xl 다음에 text-lg를 쓰면 (20px → 18px) 차이가 2px이라 계층이 안 읽힌다. 한 칸씩 건너뛰는 편이 낫다.

여기가 중요하다. 영문 기준으로 만들어진 설정을 그대로 쓰면 한글이 답답해 보인다.

한글은 글자마다 네모 칸을 꽉 채운다(전각). 영문처럼 위아래 여백이 없어서 같은 줄 간격이어도 더 빽빽해 보인다.

/* Tailwind 기본: text-base = 16px / 24px (1.5배) */
/* 한글 본문은 1.6~1.75배가 편하다 */
.prose-ko { line-height: 1.7; }
  • UI 라벨·버튼 — 기본값 그대로 (짧아서 티가 안 난다)
  • 긴 본문 문단 — leading-relaxed(1.625) 이상을 권한다

영문 폰트는 글자가 200개 남짓이라 파일이 수십 KB지만, 한글은 완성형만 11,172자라 굵기 하나에 수 MB가 된다.

방법크기언제
시스템 폰트0가장 빠르다. 기기마다 글꼴이 다른 게 괜찮다면 최선
동적 서브셋페이지당 수십 KB실제 쓰인 글자 조각만 내려받는다. 한글 웹폰트의 현실적 해답
전체 파일수 MB하지 않는다

동적 서브셋은 폰트를 수백 개 조각으로 쪼개 두고 unicode-range로 필요한 조각만 브라우저가 가져가게 하는 방식이다. Pretendard는 이 방식의 CSS를 공식 제공한다 — 구체적인 로딩 방법은 8장에서 다룬다.

<span className="font-normal">본문 400</span>
<span className="font-medium">라벨 500</span>
<span className="font-semibold">제목 600</span>
<span className="font-bold">강조 700</span>

UI에서 실제로 쓰는 건 이 넷이다. 그리고 규칙 하나 —

  • 폰트도 역할로 이름 붙인다 — --font-sans 하나면 대부분 끝난다
  • 폴백 목록을 반드시 남긴다. 없으면 로딩 실패 시 Times New Roman이 나온다
  • 크기는 스케일로만. UI 기본은 text-sm(14px), 읽는 문서는 text-base(16px)
  • 제목 계층은 한 칸씩 건너뛰어야 차이가 읽힌다
  • 한글은 규칙이 다르다 — 줄 간격은 넉넉하게, 자간은 좁히지 않고, break-keep
  • break-keep과 break-words는 한 세트다
  • 한글 웹폰트는 무겁다. 시스템 폰트 아니면 동적 서브셋
  • 굵기는 파일이 따로다. 가변 폰트를 쓰면 이 문제가 사라진다