---
id: frontend-color-spaces
title: Color Spaces — sRGB / OKLCH / P3 / Wide Gamut
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [frontend, color, design, vibe-coding]
tech_stack: { language: "CSS / Design", applicable_to: ["Frontend"] }
applied_in: []
aliases: [sRGB, OKLCH, OKLab, P3, wide gamut, color space, gradient]
---

# Color Spaces

> CSS color = 디자인 무기. **OKLCH = perceptual + 풍부, sRGB = legacy, P3 = wide gamut display**. Modern browser = 자동 best.

## 📖 핵심 개념
- sRGB: 옛 standard. 거의 모든 monitor.
- P3: Apple iPhone / Mac 의 wide gamut.
- OKLCH: perceptually uniform — L=lightness, C=chroma, H=hue.
- HSL: 옛, perceptually 비균일.

## 💻 코드 패턴

### sRGB (legacy)
```css
.box {
  background: #ff0080;
  background: rgb(255, 0, 128);
  background: hsl(330, 100%, 50%);
}
```

### OKLCH (modern, recommended)
```css
:root {
  --primary: oklch(60% 0.2 250);     /* L=60% C=0.2 H=250 */
  --accent: oklch(70% 0.18 30);
}

.button {
  background: var(--primary);
}

/* Brand 변형 */
.button:hover {
  background: oklch(from var(--primary) calc(l - 5%) c h);
}

.button:active {
  background: oklch(from var(--primary) calc(l - 10%) c h);
}
```

### Color tokens (OKLCH)
```css
:root {
  /* Primary scale */
  --primary-50: oklch(95% 0.05 250);
  --primary-100: oklch(90% 0.1 250);
  --primary-300: oklch(75% 0.15 250);
  --primary-500: oklch(60% 0.2 250);
  --primary-700: oklch(45% 0.18 250);
  --primary-900: oklch(25% 0.12 250);
}
```

→ Lightness 가 perceptually 일관 — `primary-500` 가 grade 별 같은 brightness.

### color-mix
```css
.tint {
  background: color-mix(in oklch, var(--primary) 80%, white);
}

.muted {
  background: color-mix(in oklch, var(--primary) 50%, transparent);
}

.gradient-to-success {
  background: linear-gradient(in oklch, var(--primary), var(--success));
}
```

### Wide gamut (P3)
```css
.vivid-button {
  background: oklch(70% 0.3 250);  /* P3 가능한 채도 */
}

/* @media (color-gamut: p3) {
  .vivid-button { background: color(display-p3 0.5 0.0 1.0); }
}
@media (color-gamut: srgb) {
  .vivid-button { background: oklch(...); }
} */

/* OR — color() function 직접 */
.vivid {
  background: color(display-p3 1 0.5 0);  /* sRGB 보다 풍부 */
}
```

→ iPhone / Mac display 가 더 풍부한 색 표현.

### Gradient — color space matter
```css
/* sRGB linear interp = 회색 빠짐 */
.gray-bg {
  background: linear-gradient(to right, red, blue);
  /* 중간 = 회색 (sRGB 의 한계) */
}

/* OKLCH — 일정 chroma 유지 */
.vivid-bg {
  background: linear-gradient(in oklch, red, blue);
  /* 중간 = 보라 */
}
```

→ 무지개 / brand gradient = OKLCH.

### Contrast (a11y)
```
WCAG AA: 4.5:1 (normal text), 3:1 (large)

OKLCH 의 L (lightness) 차이로 contrast 추정:
ΔL > 0.5 = OK 보통.

또는 chrome-devtools / contrast-ratio.com 정확 측정.
```

### Theme switching (light / dark)
```css
:root {
  --bg: oklch(99% 0.01 0);
  --fg: oklch(15% 0.01 0);
  --accent: oklch(60% 0.2 250);
}

.dark {
  --bg: oklch(15% 0.01 0);
  --fg: oklch(95% 0.01 0);
  --accent: oklch(70% 0.2 250);  /* dark 에 더 밝게 */
}
```

→ OKLCH 의 같은 L 만 변경 = 일관 밝기.

### accent-color (form element)
```css
:root {
  accent-color: oklch(60% 0.2 250);
}
```

```html
<input type="checkbox" />     <!-- 자동 brand 색 -->
<input type="radio" />
<input type="range" />
<progress />
```

### color-scheme
```css
:root {
  color-scheme: light dark;
}

.section { color-scheme: only light; }  /* dark mode 도 light 강제 */
```

→ Browser scrollbar / form / built-in UI 자동 따라.

### system colors
```css
.button {
  background: ButtonFace;
  color: ButtonText;
  border-color: ButtonBorder;
}

@media (forced-colors: active) {
  .button { /* Windows high contrast 자동 */ }
}
```

→ Windows High Contrast / 시스템 theme 따름.

### Color picker
```html
<input type="color" value="#ff0080" />
```

```ts
const picker = document.querySelector('input[type=color]');
picker.addEventListener('input', (e) => {
  document.documentElement.style.setProperty('--brand', e.target.value);
});
```

### Color in JS
```ts
// CSS color → OKLCH
import { converter } from 'culori';
const toOklch = converter('oklch');
const c = toOklch('#ff0080');  // { mode: 'oklch', l: 0.55, c: 0.27, h: 354 }
```

→ Tailwind 4 / shadcn 가 culori 사용.

### Tailwind 4 (default OKLCH)
```css
@theme {
  --color-primary-500: oklch(60% 0.2 250);
}
```

→ 자동 hover / active 변형 일관.

### Color blindness
```
Deuteranopia: red-green X (~5% 남자)
Protanopia: red-green X
Tritanopia: blue-yellow X (rare)

→ 색 only 정보 X — icon / text 같이.
```

```css
.error::before { content: '⚠️'; color: red; }
.success::before { content: '✓'; color: green; }
```

### sRGB vs P3 (in browser)
```
@supports (color: color(display-p3 1 0 0)) {
  /* P3 가능 */
}

# Chrome / Safari / Firefox = 모두 OKLCH + P3 지원 (2024+).
```

### OKLab vs OKLCH
```
OKLab: L, a, b (Cartesian — 직접 계산)
OKLCH: L, C, H (Polar — 직관)

→ OKLCH 가 hue rotation 자연 (`H` 만 변경).
```

### Chroma — 너무 높이면 (sRGB 가 못 표현)
```css
oklch(60% 0.4 250)  /* sRGB 가 못 표현 — clamp */
oklch(60% 0.2 250)  /* sRGB OK */
oklch(60% 0.4 250 / in display-p3)  /* P3 가능 */
```

→ Browser 가 자동 gamut clamp.

### light-dark (modern)
```css
:root {
  color-scheme: light dark;
  --bg: light-dark(white, black);
  --fg: light-dark(black, white);
}
```

→ One line, 자동 system 따라.

### Useful tools
```
oklch.com — 색 picker (modern)
huetone — accessibility-aware palette
realtimecolors.com — instant preview
Tailwind 4 generator
```

## 🤔 의사결정 기준
| 사용 | 추천 |
|---|---|
| 새 디자인 system | OKLCH |
| Gradient | in oklch |
| Brand variants | oklch + chroma adjust |
| Wide gamut display | P3 |
| Legacy support | sRGB (hex) fallback |
| Form / UI | accent-color + color-scheme |

## ❌ 안티패턴
- **HSL + variant 매번 random**: 같은 visual lightness 안 보장.
- **Hex + 큰 palette**: 변경 어려움.
- **sRGB gradient red → blue**: 중간 회색.
- **모든 색 hardcode 어디나**: theme 어려움.
- **A11y contrast 무시**: 사용자 못 봄.
- **Color only 정보**: colorblind.
- **High contrast mode 무시**: Windows 사용자.

## 🤖 LLM 활용 힌트
- OKLCH default.
- Tailwind 4 / shadcn 같이.
- Gradient = `in oklch`.
- light-dark() 가 modern theme.

## 🔗 관련 문서
- [[Frontend_Design_Tokens]]
- [[Frontend_CSS_Modern_Features]]
- [[Frontend_A11y_Testing]]
