09-design 디자인 시스템 규칙
우선순위
우선순위
이 규칙은 02-code 다음 적용된다. 코드 규칙과 충돌 시 02-code 우선.
1. 공통 금지 패턴 (Hard Bans — 항상 적용)
디자인 시스템 유무, 목업 유무, 글로벌/한국 서비스 무관하게 모든 UI 구현에 적용된다. 아래 패턴은 "AI가 만든 티"가 나거나 퀄리티 저하를 유발하므로 사용 금지.
레이아웃 & 컴포넌트
| 금지 패턴 | 대안 |
|---|---|
| 라운드박스 + 좌측/상단 컬러 보더 조합 | 카드, 인라인 레이아웃, 타이포 중심 구성 |
| 대시보드식 카드 격자 남발 (이유 없는 3열 카드) | 실제 정보 구조에 맞는 레이아웃 |
| 카드 안에 카드 (card-in-card, 3단 이상 컨테이너 중첩) | 계층 1~2단계 이내 유지 |
| 과도한 그라디언트 (여러 색 + 강한 불투명도) | 단색 또는 절제된 단방향 그라디언트 |
| 목적 없는 배경 블러 (blur 장식용 남용) | 실제 레이어 분리 목적에만 사용 |
| 아이콘 + 텍스트 모든 항목에 반복 적용 | 필요한 곳에만 아이콘 사용 |
| progress bar 장식용 남용 | 실제 진행 상태가 있을 때만 사용 |
| 뱃지/태그 모든 항목에 붙이기 | 상태 구분이 필요한 항목에만 |
| 큰 숫자 + 작은 레이블 + gradient accent bar 조합 | 정보가 진짜 대시보드일 때만 |
로고/심볼 금지 패턴:
❌ 로고 앞 네모/원 컬러 심볼 + 텍스트 조합 (AI 자동 생성 로고)
예: [■] AppName / [●] ServiceName / [◆] BrandName
이유: 실제 디자이너가 만든 로고처럼 보이려다 오히려 AI 생성 티를 냄.
무의미한 도형은 브랜드 아이덴티티가 없고 전문성이 낮아 보임.
✅ 대안:
- 텍스트 로고만 사용 (wordmark) — 폰트 굵기와 자간으로 차별화
- 실제 SVG 로고 파일이 있으면 그것을 사용
- 로고가 없으면 "로고 없음" 상태로 두고 사용자에게 보고
색상
| 금지 패턴 | 대안 |
|---|---|
| 파란 계열 + 보라 계열 기본값 (AI 최빈출 색조) | 프로젝트 고유 포인트 컬러 명시적 정의 |
| purple-to-blue gradient | 단색 또는 브랜드 기반 단방향 그라디언트 |
| 빨/주/노/초/파/남/보 6색 이상 동시 사용 | 메인 컬러 1개 + semantic 2~3색 (success/warning/error) |
| 연한 컬러 배경 + 진한 동색 보더 + 진한 텍스트 조합 (어드민 스타일) | 단일 배경색 + 텍스트 대비 확보 |
순수 흑백만 (#000, #fff) |
tinted neutral — 중성색에 색상 미량 혼합 |
하드코딩 색상값 (#xxx, rgb()) |
CSS 변수 또는 Tailwind 시맨틱 클래스 |
| 디자인 시스템 외 임의 컬러 추가 | 기존 팔레트 내에서만 선택 |
어드민 배지 패턴 구체 금지:
❌ 아래 조합을 항목마다 반복하는 패턴
bg-red-50 border border-red-200 text-red-700 "위험"
bg-yellow-50 border border-yellow-200 text-yellow-700 "주의"
bg-green-50 border border-green-200 text-green-700 "정상"
bg-blue-50 border border-blue-200 text-blue-700 "정보"
bg-purple-50 border border-purple-200 text-purple-700 "처리중"
✅ 대안: 상태값이 필요하면 텍스트 컬러 변화만으로 구분
또는 단일 neutral 배지에 아이콘/텍스트로 상태 표현
색상을 써야 하는 곳 (금지 ≠ 무채색만)
금지 목록은 남용을 막는 것이지, 색을 쓰지 말라는 뜻이 아니다. 색이 없으면 정보 구분이 어렵고, 브랜드가 사라지며, UI가 죽어 보인다.
반드시 색을 써야 하는 상황:
| 상황 | 사용 색상 | 이유 |
|---|---|---|
| Primary CTA 버튼 | 포인트 컬러 | 사용자 행동 유도 — 가장 중요한 버튼은 눈에 띄어야 함 |
| 에러 메시지 / 에러 필드 | destructive (빨간 계열) |
사용자가 즉시 인지해야 하는 정보 |
| 성공 상태 | success (초록 계열) |
완료/정상 상태 명확히 구분 |
| 경고 상태 | warning (노란/주황 계열) |
주의가 필요한 정보 |
| 링크 텍스트 | 포인트 컬러 또는 underline | 클릭 가능함을 나타냄 |
| Active / 선택된 항목 | 포인트 컬러 배경 or 텍스트 | 현재 위치/선택 상태 |
| 브랜드 로고 영역 | 브랜드 컬러 | 아이덴티티 |
semantic 컬러 3종 세트는 항상 정의되어야 한다:
"colors": {
"success": "#16a34a",
"success-foreground": "#ffffff",
"warning": "#d97706",
"warning-foreground": "#ffffff",
"destructive": "#dc2626",
"destructive-foreground": "#ffffff"
}
절제의 기준 — 한 화면에 포인트 컬러가 몇 군데?
- 적정: 1~3군데 (CTA 버튼, active 탭, 링크)
- 과다: 5군데 이상 (시선이 분산되고 중요도 구분 불가)
- 부족: 0군데 (무채색만 → 브랜드 없고 클릭 포인트 불명확)
폰트 (AI 기본값 금지)
아래 폰트는 AI 학습 데이터 최빈출값으로, 지정하지 않으면 자동으로 선택됨 — 명시적으로 금지:
| 금지 폰트 | 이유 |
|---|---|
| Inter | 글로벌 AI 기본값 — 한글 지원 없음 |
| Roboto | Android 기본값 |
| Arial | Windows 기본값 |
| system-ui / -apple-system | OS fallback — 브랜드 없음 |
한국 서비스 기본: 'Pretendard', 'Noto Sans KR', sans-serif
글로벌 서비스 기본: 레퍼런스 스타일에 맞는 폰트 지정 (섹션 6 참조)
타이포그래피
| 금지 패턴 | 대안 |
|---|---|
임의 간격값 (p-[13px], mt-[7px]) |
Tailwind 표준 스케일 (4px 단위) |
| 폰트 크기 4단계 이상 혼용 | 타입 스케일 3단계 이내 유지 |
| 굵기 3가지 이상 혼용 | 2가지 굵기만 사용 (regular + bold 또는 medium + bold) |
이모지 & 아이콘
이모지는 마크다운 문서처럼 구조적으로 꼭 필요한 곳 외에는 사용하지 않는다.
❌ 이모지 남발 패턴 (모두 금지)
🚀 빠른 시작 ← 버튼/메뉴 앞 이모지
✨ 새로운 기능 ← 카드 헤더 이모지
📊 분석 대시보드 ← 섹션 제목 이모지
💡 도움말 ← 리스트 아이템 이모지
🎉 완료되었습니다! ← 상태 메시지 이모지
❤️ 즐겨찾기 ⭐ 평점 ← 기능 설명 이모지
✅ 이모지 허용 범위
- README, CHANGELOG 같은 마크다운 문서의 섹션 구분
- 사용자가 직접 입력한 콘텐츠 (채팅, 리뷰 등)
- 사용자가 명시적으로 이모지 사용을 요청한 경우
- UI에서 아이콘이 필요하면 SVG 아이콘 라이브러리 사용 (Lucide, Heroicons 등)
- 이모지를 아이콘 대용으로 쓰는 것은 전면 금지
애니메이션
| 금지 패턴 | 대안 |
|---|---|
ease / linear (기본값) |
cubic-bezier(0.16, 1, 0.3, 1) (ease-out-expo) |
bounce easing |
자연스러운 감속 곡선 |
| 애니메이션 미구현 (정적 only) | hover/focus 전환에 transition 필수 |
/* 기본 전환 기준 */
transition: all 150ms cubic-bezier(0.16, 1, 0.3, 1);
/* prefers-reduced-motion 대응 필수 */
@media (prefers-reduced-motion: reduce) {
* { transition: none !important; animation: none !important; }
}
톤 & 표현
- 자극적/과장된 표현 금지 ("완벽한", "놀라운", "최강의")
- 흥미를 유발하되 신뢰감 있는 톤 유지
- 불신을 일으키는 마케팅성 문구 금지
2. 공통 적용 원칙 (항상)
시각적 절제
- 컬러는 메인 컬러 1개 중심 — 추가 색은 중성 톤으로 보완
- 컴포넌트 스타일은 일관되게 — 같은 역할의 컴포넌트는 같은 스타일
- 정보 계층은 크기/굵기/색상 중 한 가지 변화로 표현 — 세 가지 동시 적용 금지
- 강조는 절제 — 모든 것을 강조하면 아무것도 강조되지 않음
사용자 경험 (UX) 우선 원칙
디자인은 보기 좋은 것보다 쓰기 편한 것이 먼저다.
클릭/탭 타겟
- 버튼, 링크, 인터랙티브 요소의 최소 크기: 44×44px (모바일 기준)
- 클릭 가능한 영역이 시각적 요소보다 충분히 커야 함
입력 편의성
- 폼 필드 순서는 사용자 사고 흐름을 따름 (이름 → 이메일 → 비밀번호)
- 에러 메시지는 필드 바로 아래 즉시 표시 (submit 후 페이지 상단에만 표시 금지)
- placeholder만으로 레이블 대체 금지 — label 요소 별도 필수
- 자동완성(
autocomplete) 속성 적용
피드백
- 액션 후 200ms 이내 시각적 반응 (버튼 색 변화, 로딩 표시 등)
- 로딩 2초 이상 → 진행 상태 표시 필수
- 성공/실패 결과를 명확하게 — "처리되었습니다" 대신 "주문이 완료되었습니다"
네비게이션
- 사용자가 현재 어디 있는지 항상 알 수 있어야 함 (breadcrumb, active 상태)
- 뒤로 가기 / 취소 / 닫기는 항상 제공
상태 구현 (State Design)
모든 UI 컴포넌트는 아래 상태를 구현한다 — 누락 시 auto-fail:
| 상태 | 구현 방법 |
|---|---|
| hover | 배경색 변화 또는 underline |
| focus | ring-2 + 포인트 컬러 (접근성 필수) |
| disabled | opacity-50 + cursor-not-allowed |
| loading | skeleton 또는 spinner |
| error | 빨간 테두리 + 에러 메시지 텍스트 (필드 바로 아래) |
| empty | empty state 안내 텍스트 또는 일러스트 |
3. 한글 UI 필수 설정
한글이 포함된 UI에는 아래를 반드시 적용한다.
CSS 필수 속성
body {
font-family: 'Pretendard', 'Noto Sans KR', sans-serif;
word-break: keep-all; /* 한글 단어 중간 줄바꿈 방지 */
line-height: 1.7; /* 한글 가독성 (영문 기준 1.4보다 넉넉하게) */
letter-spacing: -0.02em; /* 한글 자간 미세 조정 */
}
한글 타이포그래피 기준
| 항목 | 영문 일반 | 한글 권장 |
|---|---|---|
| line-height | 1.4~1.5 | 1.6~1.8 |
| letter-spacing | 0 | -0.02em ~ -0.05em |
| word-break | 기본 | keep-all 필수 |
| 본문 최소 크기 | 12px 가능 | 14px 이상 (그 이하 가독성 급락) |
자주 하는 실수
word-break미설정 → 한글 단어 중간에서 줄바꿈- 행간 1.4 → 한글이 좁고 붙어 보임
- 버튼 패딩 부족 → 한글 텍스트가 버튼을 넘침
- 폰트 미지정 → OS별 다른 렌더링 (Windows/macOS/Android)
한글 폰트 선택 기준
| 폰트 | 특징 | 추천 용도 |
|---|---|---|
| Pretendard | UI 최적화, 9웨이트, 가변 폰트, 한국 스타트업 표준 | 웹/앱 UI 전반 |
| Noto Sans KR | 11,172 음절 전체 지원, Google CDN | 넓은 지원 필요 시 |
| Noto Serif KR | 명조 계열 | 에디토리얼, 아티클 |
4. 디자인 시스템 확인 절차 (UI 작업 시작 전)
프론트엔드 구현 시작 전 아래 순서로 확인한다.
1. docs/design/design-tokens.json 존재 여부 확인
2. 있으면 → 토큰 읽고 구현에 적용
3. 없으면 → 아래 "디자인 시스템 없을 때" 절차 실행
5. 디자인 시스템 없을 때
디자인 시스템(docs/design/design-tokens.json)이 없고 목업도 없을 때:
Step 1 — 서비스 성격 파악 후 레퍼런스 제안
사용자에게 아래 옵션을 제시하고 선택을 받는다:
"디자인 시스템이 없습니다. 스타일 방향을 먼저 정하겠습니다.
아래 중 가장 가까운 느낌을 선택해주세요:
[한국 서비스 스타일]
A) 토스 스타일 — 흰 배경, 강한 포인트 컬러, 원터치 UX, 금융/핀테크
B) 당근마켓 스타일 — 따뜻한 오렌지, 리스트 중심, 로컬 커뮤니티
C) 배민 스타일 — 브랜드 민트, 카테고리 강조, 푸드테크
[글로벌 서비스 스타일]
D) Linear / Vercel 스타일 — 다크 베이스, 모노톤, 개발자 도구
E) Notion 스타일 — 라이트, 깔끔, 문서/생산성
F) Stripe 스타일 — 라이트, 프리미엄, 결제/B2B
G) Shadcn/ui 기본 — 미니멀, 컴포넌트 라이브러리
H) 직접 설명해주세요"
Step 2 — 최소 디자인 시스템 생성
선택 받은 후 docs/design/design-tokens.json을 생성하고 사용자 확인 후 구현 시작:
{
"_meta": {
"style_reference": "선택된 레퍼런스명",
"locale": "ko / global",
"created": "YYYY-MM-DD",
"note": "프로젝트 디자인 시스템 초안 — 사용자 확인 필요"
},
"colors": {
"primary": "",
"primary-foreground": "",
"background": "",
"foreground": "",
"muted": "",
"muted-foreground": "",
"border": "",
"destructive": ""
},
"typography": {
"fontFamily": "",
"lineHeight": "1.7",
"letterSpacing": "-0.02em",
"scale": {
"xs": "12px", "sm": "14px", "base": "16px",
"lg": "18px", "xl": "20px", "2xl": "24px", "3xl": "30px"
},
"weight": { "normal": "400", "medium": "500", "bold": "700" }
},
"spacing": {
"unit": "4px",
"scale": [0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 80, 96]
},
"radius": {
"sm": "4px", "md": "8px", "lg": "12px", "full": "9999px"
},
"components": {
"button": { "height": "44px", "paddingX": "20px", "radius": "md" },
"input": { "height": "44px", "radius": "md" },
"card": { "radius": "lg", "padding": "20px" }
}
}
버튼/인풋 height를 44px로 기본 설정 — 모바일 터치 타겟 최소 기준 (Apple HIG 권장)
Step 3 — 토큰 없이 구현 금지
디자인 시스템 확인/생성 없이 임의 스타일로 UI 구현 시작 → auto-fail
6. 레퍼런스 스타일별 기본 토큰값
A) 토스 스타일 (Toss)
{
"colors": {
"primary": "#3182f6",
"primary-foreground": "#ffffff",
"background": "#ffffff",
"foreground": "#191f28",
"muted": "#f2f4f6",
"muted-foreground": "#6b7684",
"border": "#e5e8eb",
"destructive": "#f04452"
},
"typography": {
"fontFamily": "'Pretendard', 'Noto Sans KR', sans-serif",
"lineHeight": "1.7",
"letterSpacing": "-0.03em"
},
"_note": "흰 배경 + 파란색 포인트. 정보 위계 명확, 불필요한 장식 없음."
}
B) 당근마켓 스타일 (Karrot)
{
"colors": {
"primary": "#ff6f0f",
"primary-foreground": "#ffffff",
"background": "#ffffff",
"foreground": "#1a1a1a",
"muted": "#f5f5f5",
"muted-foreground": "#868686",
"border": "#ebebeb",
"destructive": "#e84141"
},
"typography": {
"fontFamily": "'Pretendard', 'Noto Sans KR', sans-serif",
"lineHeight": "1.6",
"letterSpacing": "-0.02em"
},
"_note": "따뜻한 오렌지. 이미지+텍스트+가격 리스트 중심."
}
C) 배민 스타일 (Baemin)
{
"colors": {
"primary": "#2ac1bc",
"primary-foreground": "#ffffff",
"background": "#ffffff",
"foreground": "#333333",
"muted": "#f8f8f8",
"muted-foreground": "#888888",
"border": "#e8e8e8",
"destructive": "#ff4444"
},
"typography": {
"fontFamily": "'Pretendard', 'Noto Sans KR', sans-serif",
"lineHeight": "1.6",
"letterSpacing": "-0.02em"
},
"_note": "민트 포인트. 카테고리 상단 노출, 텍스트 레이블 강조."
}
D) Linear / Vercel 스타일
{
"colors": {
"primary": "#ffffff",
"primary-foreground": "#000000",
"background": "#0a0a0a",
"foreground": "#ededed",
"muted": "#1a1a1a",
"muted-foreground": "#a0a0a0",
"border": "#2a2a2a",
"destructive": "#ef4444"
},
"typography": { "fontFamily": "'Geist', 'Geist Mono', sans-serif" },
"_note": "다크 모드 베이스. Inter 대신 Geist 사용."
}
E) Notion 스타일
{
"colors": {
"primary": "#2383e2",
"primary-foreground": "#ffffff",
"background": "#ffffff",
"foreground": "#1a1a1a",
"muted": "#f7f7f5",
"muted-foreground": "#787774",
"border": "#e9e9e7",
"destructive": "#eb5757"
},
"typography": { "fontFamily": "'Plus Jakarta Sans', 'Pretendard', sans-serif" },
"_note": "문서 중심. Inter 대신 Plus Jakarta Sans 사용."
}
F) Stripe 스타일
{
"colors": {
"primary": "#635bff",
"primary-foreground": "#ffffff",
"background": "#ffffff",
"foreground": "#0a2540",
"muted": "#f6f9fc",
"muted-foreground": "#425466",
"border": "#e6ebf1",
"destructive": "#df1b41"
},
"typography": { "fontFamily": "'DM Sans', 'Pretendard', sans-serif" },
"_note": "프리미엄 B2B. Sohne는 유료라 DM Sans 대체."
}
G) Shadcn/ui 기본
{
"colors": {
"primary": "#18181b",
"primary-foreground": "#fafafa",
"background": "#ffffff",
"foreground": "#09090b",
"muted": "#f4f4f5",
"muted-foreground": "#71717a",
"border": "#e4e4e7",
"destructive": "#ef4444"
},
"typography": { "fontFamily": "'Geist', sans-serif" },
"_note": "미니멀 컴포넌트. Inter 대신 Geist 사용."
}
7. 한국 서비스 UI 패턴 기준
한국 서비스 스타일(A/B/C) 선택 시 아래 패턴을 기본 적용한다.
정보 밀도 — 서비스 유형별 구분 필수
⚠️ "한국 유저 = 정보 밀도 높음"은 포털/어드민/공공 시스템 한정이다. 소비자 SaaS/앱에 이 인식을 그대로 적용하면 잘못된 방향으로 간다.
| 서비스 유형 | 정보 밀도 | 대표 사례 |
|---|---|---|
| 포털 | 높음 | 네이버, 다음 메인 |
| 어드민/사내 시스템 | 높음 | ERP, CRM, 사내 관리툴 |
| 공공/금융 레거시 | 높음 | 정부24, 인터넷뱅킹 |
| 소비자 SaaS/앱 | 낮음~중간 | 토스, 당근, 배민, 카카오뱅크 |
소비자 SaaS/앱 원칙: 토스·당근·배민은 서양 동급 서비스보다 여백을 더 넓게, 폰트를 더 크게 쓴다. 이 구분을 먼저 파악한 후 밀도를 결정한다.
업무용 SaaS (B2B): Linear/Notion 정도의 중간 밀도. 포털 수준 압축은 금지.
포털/어드민 스타일로 구현하는 경우에 한해:
- 카드에 보조 텍스트(가격, 날짜, 위치, 상태) 포함
- 리스트 아이템: 이미지 + 제목 + 보조정보 2줄 구성이 기본
- 중요 기능은 숨기지 말고 화면에 직접 노출
네비게이션
- 하단 탭바 5탭 기본 (글로벌은 4탭 권장이나 한국은 5탭이 일반적)
- 탭바 아이콘에 텍스트 레이블 항상 병기 (아이콘만 사용 금지)
- 중요 기능은 플로팅 버튼보다 탭바 배치 선호
버튼 & CTA
- 주요 CTA 버튼: full-width 스타일 (화면 하단 고정 버튼)
- 버튼 텍스트: 아이콘만 쓰지 않고 텍스트 레이블 직접 명시
- ❌
→또는 아이콘만 - ✅ "쿠폰 받기", "무료 배달", "바로 시작하기"
- ❌
바텀시트
컨텍스트 유지하며 추가 정보 제공 시 모달 대신 바텀시트 적극 사용.
8. 디자인 시스템 변경 규칙
design-tokens.json임의 수정 금지 → 사용자 승인 필요- 새 토큰 추가 시 → 이유와 값 제안 후 승인 대기
- 기존 토큰 삭제 금지 (deprecated 마킹 후 사용자 결정)
9. 커밋 전 디자인 셀프 체크
UI 변경이 포함된 커밋 전 확인:
공통 (항상)
- Hard Ban 패턴 없음 (라운드박스+보더, 다색, card-in-card 등)
- AI 기본 폰트(Inter/Roboto/Arial) 미사용
-
design-tokens.json외 임의 색상값 없음 - 이모지 남발 없음
- hover/focus/disabled 상태 구현됨
- loading skeleton / error / empty state 구현됨
- transition easing 지정됨 (ease/linear 사용 금지)
-
prefers-reduced-motion대응됨
한글 포함 시 추가
-
font-family: Pretendard또는Noto Sans KR지정됨 -
word-break: keep-all설정됨 -
line-height: 1.6이상 - 본문 폰트 14px 이상
10. 적용 범위
| 작업 | Hard Ban | 디자인 시스템 확인 | 한글 설정 |
|---|---|---|---|
| 신규 페이지/컴포넌트 구현 | 필수 | 필수 | 한글 포함 시 필수 |
| 기존 UI 대규모 변경 | 필수 | 필수 | 한글 포함 시 필수 |
| 단순 버그 수정 (1~2줄) | 필수 | 생략 가능 | 생략 가능 |
| 이메일/문서/인포그래픽 | 필수 | 생략 가능 | 한글 포함 시 필수 |
| 백엔드 전용 작업 | 적용 안 함 | 적용 안 함 | 적용 안 함 |