생성된 문서 · 직접 고치지 않는다

IZ-Get · 디자인 시스템

값은 src/index.css에서 읽어 만든다. 셸·컴포넌트는 구현 문서에 있다.

카드에 커서를 올리면 언제 쓰는 색인지 나온다. 「왜 이렇게 정했나」를 누르면 설계 근거가 열린다. 키보드로는 Tab으로 카드에 이동하면 같은 내용이 보인다.

쓰는 법

이렇게

<div className="bg-surface text-fg-muted
     border-border rounded-lg">

이렇게 말고

<div className="bg-[#fff] text-[#5a616b]"
     style={{ color: '#5a616b' }}>

하드코딩한 색은 npm run check:design이 막는다. 크기·간격에 임의값(h-[46px])을 쓰는 것은 막지 않지만, 같은 값이 세 번 반복되면 토큰으로 올린다.

쓸 토큰이 없으면 임의 색을 만들지 말고 먼저 묻는다 — 대개 이미 있는 의미에 이름을 잘못 찾고 있는 경우다.

41

값이 조정된 토큰 4개는 카드에 ✎ 표시가 있다

표면

무엇이 무엇 위에 얹히는지를 정한다

canvas #f4f5f7

페이지 배경. 카드가 얹히는 바닥이다.

예 · 매니저 화면의 콘텐츠 영역

surface #ffffff

카드·패널·모달의 면. 글자가 얹히는 기본 배경이다.

예 · 표 카드, 인증 화면의 폼 쪽

surface-2 #fafbfc

같은 카드 안에서 한 단계 눌러야 하는 면.

예 · 표 헤더 행, 기수 선택기 배경

border #e2e5ea

기본 경계선. 면을 나눌 때 쓴다.

예 · 카드 테두리, 표의 행 구분선

border-strong #cfd4dc

입력 요소처럼 경계가 또렷해야 하는 곳.

예 · 텍스트 입력, 셀렉트 테두리

왜 이렇게 정했나 (2)

배경이 왜 흰색이 아니라 회색인가

카드가 얹히는 바닥과 카드 자체를 구분하기 위해서다. 둘 다 흰색이면 카드 경계를 테두리에만 의존하게 되고, 데이터 밀도가 높은 표 화면에서 구조가 읽히지 않는다. 다만 이 차이 때문에 글자 대비를 검사할 때 두 배경을 모두 확인해야 한다.

surface와 surface-2를 왜 나눴나

표 헤더처럼 "같은 카드 안에서 한 단계 눌러야 하는 면"이 반복해서 필요했다. 그때마다 회색을 즉석에서 고르면 화면마다 다른 회색이 생긴다.

전경 (글자)

이름이 곧 역할이다. 번호가 아니다

fg #181b20

본문과 제목. 읽으라고 놓은 글자의 기본값이다.

예 · 표 셀 값, 화면 제목

fg-muted #5a616b

본문보다 한 단계 낮은 보조 설명.

예 · 입력 라벨, 화면 부제, 사용자 이름

와이어 실측: 이 색을 쓰는 CSS 규칙 236개 중 22%만 작은 글씨와 함께 쓰였다. 즉 본문 크기로도 쓰이는 보조 텍스트다.

fg-subtle #686f7d

캡션·메타 정보. 그리고 비활성·보류 상태를 색 없이 표현할 때.

예 · 측정일, 총개수, breadcrumb, 미도래 판정

SSOT의 #8b929c는 페이지 배경에서 2.88:1로 AA에 크게 못 미쳤다. 남은 시간·응시 기간처럼 판단에 쓰이는 정보에 사용되므로 장식 예외가 적용되지 않아 값을 올렸다. 와이어 실측상 이 색을 쓰는 규칙의 65%가 작은 글씨와 함께 쓰인다.

왜 이렇게 정했나 (3)

왜 text가 아니라 fg인가

Tailwind에서 글자색 유틸리티의 접두사가 이미 text-다. 토큰 이름까지 text로 하면 text-text-2가 되어 같은 말이 두 번 나온다. fg(foreground)는 배경(bg)과 짝이 맞는 표준 어휘이고, text-fg-muted처럼 읽힌다.

왜 1·2·3 번호가 아니라 muted·subtle인가

번호는 "무엇에 쓰는 색인지"를 말해주지 않는다. 실제로 와이어에서 사용처를 세어보니 셋째 단계는 65%가 작은 글씨와 함께 쓰이는 캡션·메타용이었다. 역할이 이름이 되면 문서를 안 봐도 어디 쓸지 짐작할 수 있다.

비활성·보류는 무슨 색인가

fg-subtle이다. 회색이지 의미 색이 아니다. 비활성을 danger로 칠하면 "위험"과 "지금은 해당 없음"이 같은 색이 되어 화면이 거짓말을 한다.

브랜드

액센트는 하나뿐이다

primary #3a4db8

주 액션과 선택 상태, 그리고 링크.

예 · 로그인 버튼, 선택된 탭, 텍스트 링크

절제된 단일 액센트다. 강조하고 싶다고 의미 색(danger·warning)을 쓰지 않는다 — 그건 상태를 뜻한다.

primary-hover #31429e

주 액션 위에 커서가 올라갔을 때.

예 · 버튼 hover

primary-soft #eef0fb

선택되었음을 배경으로 알릴 때.

예 · 선택된 표 행, 아바타 배경

primary-border #cdd4f2

primary-soft 면의 테두리.

예 · 선택된 카드의 윤곽

brand-1 #31429e

인증 화면 좌측 패널 그라디언트의 시작색.

예 · 로그인·회원가입·계정 활성화 화면

인증 화면 전용이다. 앱 내부 화면에는 이 그라디언트를 쓰지 않는다.

brand-2 #232a4d

같은 그라디언트의 끝색.

예 · 위와 동일

왜 이렇게 정했나 (2)

액센트가 왜 하나뿐인가

이 제품의 디자인 방향이 "조용한 뉴트럴 베이스 + 절제된 단일 액센트"다. 상태는 의미 색으로만 말한다. 액센트가 여럿이면 무엇이 주 액션인지 흐려진다.

강조하고 싶은데 primary가 약해 보이면

의미 색을 강조 용도로 쓰지 않는다. danger는 빨간색이 아니라 "위험"이라는 뜻이고, 강조 목적으로 쓰면 사용자가 위험 신호를 무시하기 시작한다. 크기·굵기·배치로 강조한다.

의미 색

같은 의미 = 항상 같은 색. 화면에서 임의 색을 신설하지 않는다

danger #c0392b

위험·차단·에러. 그리고 하락 시그널.

예 · 인증 실패 문구, 권한 차단 안내, 비활성 계정

danger-soft #fbeceb

위험 알림의 배경면.

예 · 폼 상단 에러 알림

danger-border #f0cdc9

위험 알림의 테두리.

예 · 동일

warning #96631a

주의·표본 부족·미검증·일시 잠금. 아직 판단할 수 없거나 조건부인 상태.

예 · 계정 잠금 안내, 미검증 이메일 배너, 표본 부족 표시

SSOT의 #b3771a는 3.77:1로 AA 미달이었다. 경고 문구가 가장 안 읽히는 우선순위 역전이 생겨 값을 어둡게 올렸다. 배경색(warning-soft)은 그대로다.

warning-soft #fbf3e6

주의 알림의 배경면.

예 · 잠금 안내 박스

warning-border #e6d3a8

주의 알림의 테두리.

예 · 동일

success #1a7d52

정상·활성·회복·승인.

예 · 활성 계정 배지, 회복 판정, 승인된 교안

SSOT의 #1f8a5b는 4.33:1로, AA 기준에서 0.17 모자랐다. 눈으로는 구분할 수 없는 차이여서 앞선 감사에서도 지적되지 않았고 계산해서 발견했다.

success-soft #e8f5ee

정상·완료 알림의 배경면.

예 · 완료 안내

success-border #b7dfc9

정상·완료 알림의 테두리.

예 · 동일

info #2f6bb0

정보·안내·온디맨드. 사용자가 다음 행동을 고를 수 있는 안내.

예 · 인증 메일 재발송 안내, 근거 패널

info-soft #eaf2fa

정보 알림의 배경면.

예 · 재발송 안내 박스

info-border #c5daf0

정보 알림의 테두리.

예 · 동일

neutral-soft #e0e3ea

의미가 없는 회색 면. 상태를 뜻하지 않는 구분에 쓴다.

예 · 비활성 토글 트랙, 중립 태그

왜 이렇게 정했나 (3)

같은 의미에 항상 같은 색을 쓰는 이유

사용자가 색을 학습하게 하려는 것이다. 한 화면에서 회복이 초록이었는데 다른 화면에서 파랑이면, 색은 아무 정보도 주지 못하는 장식이 된다. 새 상태가 생기면 임의 색을 만들지 말고 SSOT 매핑표에 추가한다.

색만으로 상태를 표현해도 되나

안 된다. 색을 구분하기 어려운 사용자에게 정보가 전달되지 않는다. 이 제품의 와이어는 이미 색 옆에 텍스트를 함께 둔다(진행도 옆 2/4, 판정 옆 견고·부분·표면). 그 규칙을 유지한다.

soft와 border는 언제 쓰나

알림·배지처럼 면이 필요한 경우에 셋이 한 벌로 움직인다 — 글자는 진한 색, 배경은 soft, 테두리는 border. 셋을 섞어 쓰면 대비가 무너진다.

어두운 면 (좌측 네비)

밝은 배경용 색은 어두운 면에서 통하지 않는다

nav #1e2436

좌측 네비게이션 바탕.

예 · 매니저·슈퍼어드민 셸의 사이드바

nav-active #2a3147

현재 보고 있는 메뉴 항목의 배경.

예 · 선택된 nav 항목

nav-fg #aeb4c6

어두운 네비 위의 글자.

예 · 선택되지 않은 메뉴 이름

nav-accent #d9a441

어두운 면 위의 강조.

예 · 총괄 전용 메뉴에 붙는 배지

밝은 배경용 warning을 그대로 쓰면 어두운 네비 위에서 3.01:1로 미달한다. 밝은 쪽을 위해 어둡게 만든 색이기 때문이다. 어두운 면에는 별도 색이 필요하다.

왜 이렇게 정했나 (2)

네비만 왜 색을 따로 갖나

어두운 배경 위에서는 밝은 배경용 색이 그대로 통하지 않는다. 밝은 쪽에서 읽히게 하려고 어둡게 만든 색은 어두운 배경에서 오히려 안 읽힌다. 실제로 총괄 배지에 밝은 배경용 warning을 썼다가 3.01:1로 미달한 것을 계산해서 발견했다.

다크 모드와는 다른가

다르다. 이건 특정 영역(사이드바)이 어두운 것이고, 다크 모드는 전체 테마가 뒤집히는 것이다. 다크 모드 요구는 현재 명세에 없다.

그 외

위 분류에 속하지 않는 것. 우리가 정의한 토큰이 여기 나타나면 분류가 빠진 것이다.

reach-0 #df6150
reach-1 #ec9a5c
reach-2 #ecc95e
reach-3 #a9cf8e
reach-4 #57b083
reach-fg #241108
reach-na-bg #eceef1
code #1e2436
code-fg #d6dae6
code-dim #8992a6

글자 크기 8

데이터 밀도가 높은 운영 도구라 기준이 14px다(웹 기본 16px 아님)

text-2xs11px다람쥐 헌 쳇바퀴에 타고파
text-xs12px다람쥐 헌 쳇바퀴에 타고파
text-sm13px다람쥐 헌 쳇바퀴에 타고파
text-base14px다람쥐 헌 쳇바퀴에 타고파
text-lg16px다람쥐 헌 쳇바퀴에 타고파
text-xl20px다람쥐 헌 쳇바퀴에 타고파
text-2xl26px다람쥐 헌 쳇바퀴에 타고파
text-3xl32px다람쥐 헌 쳇바퀴에 타고파
왜 이렇게 정했나 (2)

왜 기본이 16px이 아닌가

한 화면에 표·지표·목록이 함께 놓이는 운영 도구다. 16px 기준으로 잡으면 표가 한 화면에 안 들어와 스크롤이 늘고, 그러면 비교가 어려워진다. 대신 대비를 AA로 유지해 작아도 읽히게 했다.

2xs·3xl은 어디 쓰나

2xs(11px)는 확정 화면 실측에서 가장 많이 쓰인 크기(148회)라 뒤늦게 승격했다 — 배지·메타·표의 보조 정보. 3xl은 인증 화면의 마케팅 헤드라인 전용이다.

font-sans

다람쥐 Sphinx 0123

font-mono

다람쥐 Sphinx 0123

왜 이렇게 정했나 (1)

왜 웹폰트를 안 쓰나

한글 웹폰트는 용량이 크고, 라틴 전용 폰트를 넣어봐야 한글은 결국 시스템 폰트로 폴백된다. 얻는 것보다 첫 화면이 느려지는 비용이 크다고 봤다.

모서리 · 그림자 5

rounded-sm · 6px
rounded-md · 10px
rounded-lg · 14px
rounded-xl · 18px
shadow-card
왜 이렇게 정했나 (1)

그림자가 왜 하나뿐인가

이 제품에서 떠 있어야 하는 것은 카드뿐이다. 모달은 배경을 덮어 구분되고, 나머지는 테두리로 나뉜다. 그림자 단계를 여럿 두면 "얼마나 떠 있나"를 매번 고민하게 된다.