Colors
SPI 디자인 시스템의 색상 팔레트, 시맨틱 매핑, 테마 전략 가이드입니다.
Colors
SPI 디자인 시스템은 3단계 색상 아키텍처를 사용합니다. Primitive(원시 팔레트) → Semantic(역할 매핑) → Component(컴포넌트 전용) 순서로 참조하며, 테마(Light/Dark) 전환은 Semantic 레이어에서 자동으로 처리됩니다.
Primitive Palette
직접 사용하기보다 Semantic 토큰을 정의하는 데 쓰이는 기초 색상 팔레트입니다. 50이 가장 밝고 950이 가장 어둡습니다.
Brand (브랜드 메인)
50
#eef2f6
Light background
100
#dde6ee
Hover background
200
#bccddc
300
#9ab3cb
Dark ring
400
#789aba
Dark primary
500
#5781a8
Light ring
600
#456787
Light primary
700
#344d65
Dark primary hover
Accent (브랜드 보조)
50
#eef6f5
100
#dcecea
200
#b9d9d5
300
#96c6c0
Dark accent
400
#73b3ac
Dark secondary
500
#509f97
Light accent
600
#3f7f78
Light secondary
700
#2f5f5a
Gray (중립색)
텍스트, 배경, 테두리 등 UI 전반에 가장 많이 사용되는 색상입니다.
50
#f6f8fa
Light bg / Dark text
100
#edf1f4
Light surface
200
#d6dde3
Light border
300
#bfc9d1
Light input
400
#9aa6b2
Light disabled text
500
#8490a0
600
#6f7c8a
Light secondary text
700
#4f5a66
Dark input
800
#313a43
Dark border
900
#1b2127
Light text / Dark surface
950
#12171c
Dark bg
Status Colors (상태색)
Error 500
#e16b64
Dark error
Error 600
#c84f48
Light error
Success 500
#4fa88b
Dark success
Success 600
#3e8a72
Light success
Warning 300
#f4dd9b
Dark warning
Warning 500
#e2bf5a
Light warning
Info 500
#5781a8
Dark info
Info 600
#456787
Light info
Semantic Colors
특정 역할(용도)에 매핑된 색상입니다. 개발 시에는 반드시 Semantic 토큰을 사용해야 합니다. 테마가 전환되면 같은 토큰 이름에 다른 Primitive 값이 자동으로 매핑됩니다.
Light / Dark 비교
| Role Token | Light Theme | Dark Theme |
|---|---|---|
background.normal var(--color-background-normal) | Static White #FFFFFF | Gray 950 #12171c |
background.neutral var(--color-background-neutral) | Gray 50 #f6f8fa | Gray 900 #1b2127 |
fill.primary.strong var(--color-fill-primary-strong) | Brand 600 #456787 | Brand 400 #789aba |
fill.primary.normal var(--color-fill-primary-normal) | Brand 400 #789aba | Brand 300 #9ab3cb |
fill.secondary.strong var(--color-fill-secondary-strong) | Accent 600 #3f7f78 | Accent 400 #73b3ac |
fill.secondary.normal var(--color-fill-secondary-normal) | Accent 400 #73b3ac | Accent 300 #96c6c0 |
fill.grayscale var(--color-fill-grayscale) | Gray 200 #d6dde3 | Gray 800 #313a43 |
foreground.strong var(--color-foreground-strong) | Gray 900 #1b2127 | Gray 50 #f6f8fa |
foreground.normal var(--color-foreground-normal) | Gray 600 #6f7c8a | Gray 300 #bfc9d1 |
foreground.assistive var(--color-foreground-assistive) | Gray 400 #9aa6b2 | Gray 500 #8490a0 |
foreground.inverse var(--color-foreground-inverse) | Static White #FFFFFF | Gray 950 #12171c |
foreground.disabled var(--color-foreground-disabled) | Gray 300 #bfc9d1 | Gray 600 #6f7c8a |
border.strong var(--color-border-strong) | Gray 400 #9aa6b2 | Gray 600 #6f7c8a |
border.normal var(--color-border-normal) | Gray 200 #d6dde3 | Gray 800 #313a43 |
border.assistive var(--color-border-assistive) | Gray 100 #edf1f4 | Gray 900 #1b2127 |
status.error var(--color-status-error) | Error 600 #c84f48 | Error 500 #e16b64 |
status.success var(--color-status-success) | Success 600 #3e8a72 | Success 500 #4fa88b |
status.warning var(--color-status-warning) | Warning 500 #e2bf5a | Warning 300 #f4dd9b |
status.info var(--color-status-info) | Info 600 #456787 | Info 500 #5781a8 |
accent.selected var(--color-accent-selected) | Accent 500 #509f97 | Accent 300 #96c6c0 |
static.white var(--color-static-white) | Static White #FFFFFF | Static White #FFFFFF |
static.black var(--color-static-black) | Static Black #000000 | Static Black #000000 |
static.transparent var(--color-static-transparent) | Transparent transparent | Transparent transparent |
테마 전환 전략
Light 테마에서는 팔레트의 600 단계(어두운 쪽)를, Dark 테마에서는 300~400 단계(밝은 쪽)를 사용합니다. 이렇게 하면 배경과의 명도 대비(Contrast Ratio)가 충분히 확보됩니다.
shadcn/ui 호환 변수
SPI는 shadcn/ui 컴포넌트와 호환되도록 다음 CSS Variable을 자동 생성합니다. 모든 shadcn 변수는 우리 Primitive 팔레트를 참조합니다.
| Role Token | Light Theme | Dark Theme |
|---|---|---|
background var(--background) | Gray 50 #f6f8fa | Gray 950 #12171c |
foreground var(--foreground) | Gray 900 #1b2127 | Gray 50 #f6f8fa |
primary var(--primary) | Brand 600 #456787 | Brand 400 #789aba |
secondary var(--secondary) | Accent 600 #3f7f78 | Accent 400 #73b3ac |
muted var(--muted) | Gray 200 #d6dde3 | Gray 800 #313a43 |
accent var(--accent) | Accent 500 #509f97 | Accent 300 #96c6c0 |
destructive var(--destructive) | Error 600 #c84f48 | Error 500 #e16b64 |
card var(--card) | Gray 50 #f6f8fa | Gray 900 #1b2127 |
popover var(--popover) | Gray 50 #f6f8fa | Gray 900 #1b2127 |
border var(--border) | Gray 200 #d6dde3 | Gray 800 #313a43 |
input var(--input) | Gray 300 #bfc9d1 | Gray 700 #4f5a66 |
ring var(--ring) | Brand 500 #5781a8 | Brand 300 #9ab3cb |
사용법
Tailwind 클래스 (권장)
// 배경색
<div className="bg-background" />
<div className="bg-primary" />
// 텍스트
<p className="text-foreground" />
<p className="text-muted-foreground" />
// 테두리
<div className="border border-border" />CSS Variable 직접 사용
.my-custom-card {
background-color: var(--color-background-neutral);
color: var(--color-foreground-strong);
border: 1px solid var(--color-border-normal);
}하지 말아야 할 것
/* ❌ HEX 하드코딩 금지 */
.card {
background: #f6f8fa;
color: #1b2127;
}
/* ✅ 토큰 사용 */
.card {
background: var(--color-background-normal);
color: var(--color-foreground-strong);
}