oklch()는 색을 밝기(Lightness)·채도(Chroma)·색상(Hue) 세 축으로 표현하는 CSS 색상 함수다. 사람의 시지각에 맞춰 설계돼, 같은 L 값이면 색상이 달라도 밝기가 비슷하게 느껴진다. 이 "지각적 균일성" 덕분에 디자인 토큰 팔레트를 예측 가능하게 만들 수 있다.
나는 오랫동안 HSL로 팔레트를 짰다. 그런데 HSL은 배신을 자주 한다. 같은 L값인데 노랑은 눈부시고 파랑은 칙칙하다. oklch로 옮기고 나서야 "아, 색이 계산대로 나오는구나"를 처음 느꼈다.
HSL은 왜 배신하는가
HSL의 L(명도)은 수학적 정의일 뿐 사람 눈의 밝기와 어긋난다. hsl(60 100% 50%)(노랑)과 hsl(240 100% 50%)(파랑)은 L이 똑같이 50%지만, 실제로 노랑이 훨씬 밝아 보인다. 그래서 HSL로 만든 색상환 팔레트는 어떤 색은 텍스트가 잘 읽히고 어떤 색은 안 읽히는 들쭉날쭉함이 생긴다.
oklch의 L은 다르다. 지각 밝기에 맞춰져 있어, L을 고정하고 Hue만 돌리면 밝기 인상이 유지된다. 이게 팔레트 설계에서 결정적이다.
문법
/* oklch(L C H) */
color: oklch(0.72 0.15 250);
/* ↑ ↑ ↑
밝기 0~1 채도 색상 각도(0~360) */
/* 알파는 슬래시로 */
background: oklch(0.72 0.15 250 / 0.2);
- L: 0(검정)~1(흰색). 0.5 근처가 중간 밝기.
- C: 채도. 0이 무채색, 커질수록 선명. 대략 0.4까지.
- H: 색상 각도. 0/360 빨강, 140 초록, 250 파랑 근처.
디자인 토큰 팔레트 만들기
실전에서 진가가 나온다. 브랜드 색 하나를 정하고, L만 계단식으로 바꿔 명도 스케일(50~900)을 뽑는다. Hue와 Chroma를 고정하니 색조가 흔들리지 않는다.
:root {
--brand-h: 255;
--brand-c: 0.13;
--brand-50: oklch(0.97 0.02 var(--brand-h));
--brand-100: oklch(0.93 0.05 var(--brand-h));
--brand-500: oklch(0.62 var(--brand-c) var(--brand-h));
--brand-700: oklch(0.48 0.12 var(--brand-h));
--brand-900: oklch(0.30 0.08 var(--brand-h));
}
여기에 상대 색상 문법(relative color)을 더하면 한 색에서 파생색을 계산으로 뽑을 수도 있다.
/* 브랜드색을 받아 L만 낮춰 hover 색 생성 */
--brand-hover: oklch(from var(--brand-500) calc(l - 0.08) c h);
oklch를 쓰면 좋은 이유
| 기능 | HSL/HEX | oklch |
|---|---|---|
| 밝기 일관성 | 색상마다 제각각 | L 고정 시 균일 |
| 넓은 색역(P3) | sRGB 한정 | 표현 가능 |
| 보간(그라데이션) | 중간에 회색빛 | 깔끔하게 이어짐 |
개인적으로 가장 체감되는 건 그라데이션이다. HEX 두 색을 섞으면 중간이 탁하게 죽는 경우가 잦은데, oklch 보간은 중간색이 자연스럽다. background: linear-gradient(in oklch, ...)로 색 공간을 지정하면 된다.
주의점
넓은 색역을 쓸 수 있다는 건 반대로 sRGB 범위를 벗어나 화면에서 잘릴(clip) 수 있다는 뜻이기도 하다. C를 너무 높이면 일반 모니터에선 표현이 뭉개진다. 실무에선 C를 적당히(0.15 안팎) 잡고, 중요한 색은 실제 디스플레이에서 확인하는 습관이 필요하다. 아주 오래된 브라우저를 지원해야 한다면 @supports로 폴백 HEX를 함께 두자.
자주 묻는 질문
oklch와 oklab은 뭐가 다른가요?
같은 OKLab 색 공간을 좌표계만 다르게 표현합니다. oklch는 극좌표(채도·각도)라 사람이 직관적으로 조정하기 쉽고, oklab은 직교좌표라 계산·보간에 편합니다. 팔레트 설계엔 oklch가 편합니다.
디자인 도구가 oklch를 지원하나요?
최근 디자인 툴과 컬러 유틸리티들이 oklch 입출력을 지원합니다. 지원이 애매하면 HEX로 뽑은 뒤 변환기로 oklch 값을 얻어 토큰에 넣는 방식도 실용적입니다.
접근성 대비(명암비)는 어떻게 확인하나요?
WCAG 대비 계산은 sRGB 상대 휘도 기반이라, oklch의 L값과 직접 일치하진 않습니다. 대비는 반드시 별도 대비 검사 도구로 확인하세요.
브라우저 지원은 충분한가요?
주요 브라우저 모두 지원해 실무 적용 가능한 수준입니다. 상대 색상 문법(from) 지원은 그보다 최근이니, 필요하면 기능 감지로 폴백을 두는 게 안전합니다.

댓글 0