토큰 및 변수 전략
반복되는 값을 임의로 작성하지 않고, 토큰과 변수를 통해 일관되게 관리하는 것을 원칙으로 합니다. 이 전략은 스타일 변경을 구조 변경으로 번지지 않게 하기 위한 기준입니다.
토큰과 변수의 역할
섹션 제목: “토큰과 변수의 역할”토큰과 변수는 다음 역할을 담당합니다.
- 디자인 값의 단일 출처 역할을 합니다.
- 프로젝트 전반의 일관성을 유지합니다.
- 수정 범위를 최소화합니다.
- 스타일 변경의 영향을 예측 가능하게 합니다.
토큰은 구조를 대체하지 않으며, 구조 위에서만 작동합니다.
토큰 사용 원칙
섹션 제목: “토큰 사용 원칙”토큰은 다음 원칙을 따릅니다.
- 반복되는 값은 반드시 토큰으로 관리합니다.
- 임의의 숫자나 색상 값 사용을 지양합니다.
- 의미 없는 값 나열을 허용하지 않습니다.
- 토큰은 역할과 목적이 드러나야 합니다.
토큰은 값 자체가 아니라 의미를 담은 단위입니다.
의미 기반 토큰은 :root에 선언하며, 이름에 역할과 목적이 드러나야 합니다.
rem 값에는 px 환산 주석을 함께 답니다.
:root { --color_primary: #2563eb; --color_text: #1a1a1a; --color_border: #e5e7eb; }:root { --space_sm: 0.5rem; /* 8 */ --space_md: 1rem; /* 16 */ --space_lg: 1.5rem; /* 24 */ }:root { --radius_md: 8px; --radius_lg: 16px; }토큰 추가 기준
섹션 제목: “토큰 추가 기준”토큰은 실제 사용처가 생길 때만 추가합니다.
- 완비된 스케일(모든 단계를 미리 채운 토큰 세트)을 만들지 않습니다.
- 사용되지 않는 토큰은 삭제 대상입니다.
- 반복되는 임의값은 가장 가까운 스케일 값으로 스냅해 토큰으로 흡수합니다. (예:
18px → var(--space_md)) - 임의값이 반복되고 있다면 토큰 부재의 신호로 판단합니다.
2계층 토큰(색상의 원료 → 역할)에서는 “사용”의 정의가 계층마다 다릅니다.
- 원료(프리미티브)의 사용 = 역할 레이어가 참조하는 것. 라이트·다크 두 테마가 같은 사다리를 반대편에서 소비하므로, 컴포넌트 코드에 보이지 않아도 사용 중일 수 있습니다.
- 역할(시맨틱)의 사용 = 컴포넌트가 참조하는 것.
어느 계층이든 참조가 0회인 토큰은 삭제 대상입니다.
예외는 z-index입니다. z-index는 개별 값이 아니라 레이어 간 순서 계약이므로, 아직 사용되지 않는 중간 레이어도 유지합니다.
눈금 토큰의 값은 불변입니다
섹션 제목: “눈금 토큰의 값은 불변입니다”토큰의 가치는 이름과 값 사이의 간격에서 나옵니다.
--color_text는 이름(역할)과 값이 분리되어 있어 테마에 따라 값을 바꿀 수 있습니다.--space_8은 이름이 곧 값입니다. 값을 바꾸는 순간 이름이 거짓말을 합니다.
그래서 이름이 곧 값인 토큰(눈금 토큰)은 값을 절대 바꾸지 않습니다.
눈금 토큰은 치환 장치가 아니라 자의 눈금입니다.
- 고를 수 있는 값의 선택지를 좁히고 (임의값 유입 차단)
- 단위 정책(rem)을 표기 자체로 집행합니다.
“값을 바꾸고 싶다”는 요구는 둘 중 하나이며, 어느 쪽도 눈금을 옮기지 않습니다.
특정 자리의 간격을 키우고 싶은 경우 값 변경이 아니라 선택 변경입니다. 해당 사용처만 다른 눈금으로 재배정합니다.
/* 이 자리가 답답하다면 — 눈금이 아니라 선택을 바꾼다 */.card .i_foot { gap: var(--space_8); } /* 이전 */.card .i_foot { gap: var(--space_12); } /* 이후 */시스템 전역의 간격을 함께 조정하고 싶은 경우 눈금 위에 역할(시맨틱) 별칭 레이어를 얹습니다. 색상의 원료 → 역할 2계층과 같은 구조입니다.
/* 역할 토큰만 재배선하면 전역에 반영된다 */:root { --control_pad_x: var(--space_16); }[data-density="compact"] { --control_pad_x: var(--space_12); }단, 역할 레이어는 전역 연동 수요가 실증될 때 추가합니다. 미리 만들면 미사용 토큰이 됩니다.
간격에 생값(8px, 0.5rem)을 직접 쓰지 않습니다.
유일한 예외는 단위 기준에서 정한
레이아웃 구조 간격(px 직접 사용 영역)입니다.
단위 기준 — rem과 px
섹션 제목: “단위 기준 — rem과 px”단위는 취향이 아니라 다음 질문으로 판정합니다.
사용자가 브라우저 글자 크기를 키웠을 때, 이 값이 함께 커져야 정보 전달이 유지되는가?
rem을 사용하는 값 — 글자 선호에 반응해야 하는 값
- 글자 크기
- 텍스트를 담는 컨트롤의 높이와 패딩
- 텍스트 주변 간격 (space 토큰)
글자만 커지고 그릇이 커지지 않으면 텍스트가 잘리고, 정보 전달이 실패합니다.
px를 사용하는 값 — 글자 선호와 무관한 값
- 라디우스, 1px 헤어라인 보더, 그림자
- 브레이크포인트
- 레이아웃 구조 간격 (그리드 갭, 섹션 여백)
- 비주얼 타이포그래피 (히어로, 랜딩)
- 애니메이션 측정값
이 값들까지 rem이면 글자 크기만 키웠을 때 레이아웃 전체가 거대해지는 다른 종류의 파손이 생깁니다.
em을 사용하는 값 — 부모 텍스트에 비례해야 하는 값
- 텍스트와 나란히 의미를 전달하는 아이콘 크기
.btn svg { width: 1.125em; height: 1.125em; }아이콘이 em이면 글자 확대와 크기 변형(m_small/m_large)에
자동으로 연동됩니다. SVG의 width/height 속성으로
크기를 고정하지 않습니다.
전면 rem도, 전면 px도 아닙니다. 기준 없는 혼용이 문제이며, 위 질문이 그 기준입니다.
루트 폰트 크기는 100%(16px)를 유지합니다.
62.5% 같은 환산 트릭은 브라우저 최소 폰트 크기 설정에서
배율이 붕괴하고, 미디어쿼리의 rem과 이중 기준이 생기므로
사용하지 않습니다. 환산은 px 주석으로 해결합니다.
변수 사용 기준
섹션 제목: “변수 사용 기준”CSS 변수는 다음 기준에 따라 사용합니다.
- 색상, 여백, 크기, 레이아웃 값에 사용합니다.
- 구조를 표현하는 용도로 사용하지 않습니다.
- 상태 표현을 직접 담당하지 않습니다.
변수는 스타일 구현 수단이며, 구조 설계 도구가 아닙니다.
컴포넌트에서는 값을 직접 쓰지 않고 var()로 토큰을 참조합니다.
/* ❌ 나쁜 예 — 하드코딩된 값이 흩어져 유지보수가 어려움 */.card { padding: 16px; border: 1px solid #e5e7eb; border-radius: 8px; }.card .i_title { color: #1a1a1a; }/* ✅ 좋은 예 — 의미 기반 토큰을 var()로 참조 */.card { padding: var(--space_md); border: 1px solid var(--color_border); border-radius: var(--radius_md); }.card .i_title { color: var(--color_text); }토큰과 구조의 관계
섹션 제목: “토큰과 구조의 관계”구조와 토큰의 역할은 명확히 분리합니다.
- 구조는 클래스와 네이밍으로 정의합니다.
- 값은 토큰과 변수로 관리합니다.
- 구조 변경 없이 값만 교체할 수 있어야 합니다.
토큰이 구조를 침범하기 시작하면 설계가 잘못되었다고 판단합니다.
파일 분할과 로드
섹션 제목: “파일 분할과 로드”토큰 소스는 카테고리별 파일로 나눠 관리합니다. 이것은 저작 구조 — 사람이 편집하기 위한 조직입니다.
단, @import 구문이 브라우저에 그대로 도달하게 하지 않습니다.
브라우저는 진입 파일을 파싱한 뒤에야 임포트 대상을 발견하므로
순차 폭포(waterfall)가 생겨 렌더링을 지연시킵니다.
- 빌드(번들)를 거치는 배포 — 진입점과
@import를 사용해도 됩니다. 빌드 타임에 한 파일로 합쳐져 런타임 비용이 없습니다. - 빌드 없이 서빙 —
@import대신 개별<link>를 나열합니다. HTML 파싱 시점에 전부 발견되어 병렬로 로드됩니다.
웹폰트는 시스템 CSS가 강제 로드하지 않습니다.
소비자 페이지가 <link>로 직접 넣습니다.
토큰 전략의 목적
섹션 제목: “토큰 전략의 목적”토큰 및 변수 전략은 UI 스타일을 통제하기 위한 규칙이 아니라, UI 구조를 안정적으로 유지하기 위한 보호 장치입니다.
토큰이 정리될수록 UI 구조는 더 단순하고 유지보수하기 쉬워집니다.