사장님이 로고 파일을 보내주시면서 이렇게 말씀하시는 일이 꽤 있습니다. "이 파랑이 우리 색인데, 웹사이트에 올리니까 좀 죽었어요." 디자이너가 인쇄물에서 쓰던 그 쨍한 파랑이, 브라우저에 올라가는 순간 한 톤 가라앉아 보이는 겁니다. 코드를 뜯어봐도 색상값은 정확합니다. 그런데도 눈에는 다르게 보입니다.
원인은 값이 아니라 그 값이 놓인 좌표계에 있습니다. 지금까지 웹의 색은 거의 전부 sRGB라는 낡은 상자 안에서만 움직였고, 그 상자는 요즘 화면이 실제로 낼 수 있는 색의 일부만 담고 있습니다. 최근 몇 년 사이 브라우저들이 이 상자 밖으로 나가는 길을 열었습니다. oklch와 display-p3입니다.
sRGB는 1996년에 정해진 상자입니다
우리가 평소 쓰는 #0066FF 같은 16진수 코드, rgb(), hsl()은 모두 sRGB라는 색 공간 위에 찍힌 좌표입니다. sRGB는 1996년, CRT 모니터가 표준이던 시절에 "대부분의 화면이 낼 수 있는 색"의 공통분모로 정해졌습니다.
문제는 30년이 지났다는 것입니다. 요즘 아이폰, 맥북, 아이패드, 중급 이상 안드로이드 폰의 화면은 sRGB보다 훨씬 넓은 display-p3 색역을 냅니다. 특히 선명한 빨강, 초록, 청록 쪽에서 차이가 큽니다. sRGB로만 색을 지정하면, 손님 주머니 속 화면이 낼 수 있는 색의 상당 부분을 처음부터 포기하고 시작하는 셈입니다.
인쇄 브랜드 컬러가 웹에서 죽어 보이는 이유도 대개 여기에 있습니다. 그 색이 애초에 sRGB 상자 밖에 있던 색이라, 상자 안으로 억지로 밀어 넣는 과정에서 채도가 깎여나간 겁니다.
oklch — 사람 눈의 감각에 맞춘 좌표계
oklch는 색을 세 가지 값으로 적습니다. L(밝기), C(채도), H(색상 각도)입니다. hsl과 비슷해 보이지만 결정적인 차이가 하나 있습니다. oklch의 밝기는 사람 눈이 느끼는 밝기와 일치하도록 설계됐습니다.
실무에서 이 차이는 이렇게 드러납니다. hsl에서 명도를 50%로 맞춘 파랑과 노랑을 나란히 두면, 노랑이 훨씬 밝아 보입니다. 같은 숫자인데 눈에는 전혀 같지 않죠. 그래서 "버튼 색 계열을 여섯 개 만드는데 왜 노란색만 붕 떠 보이지?" 같은 상황이 생기고, 결국 디자이너가 눈대중으로 하나씩 보정하게 됩니다.
oklch에서는 L 값을 같게 맞추면 실제로 같은 밝기로 보입니다. 덕분에 이런 일이 쉬워집니다.
- 브랜드 색 하나에서 H를 고정한 채 L만 바꿔 10단계 색조를 일관되게 뽑아내기
- 색상별로 들쭉날쭉하지 않은 상태 색(성공·경고·오류) 세트 만들기
- 다크 모드로 뒤집을 때 L 값만 반전시켜 채도를 유지하기
- 본문 글자와 배경의 대비를 예측 가능하게 관리하기
무엇보다 oklch는 sRGB 상자에 갇혀 있지 않습니다. 표현할 수 있는 좌표가 화면의 색역만큼 넓어서, 지금까지 적을 방법이 없던 색도 적을 수 있습니다.
display-p3 — 상자 밖의 색을 실제로 쓰기
색역을 명시적으로 지정하려면 color() 함수를 씁니다. color(display-p3 0 0.5 1) 같은 식입니다. 이렇게 적으면 P3를 지원하는 화면에서는 sRGB로는 낼 수 없던 선명한 색이 그대로 나옵니다.
여기서 걱정이 생깁니다. "그럼 오래된 모니터에서는 색이 깨지나요?" 아닙니다. 브라우저는 지원하지 않는 값을 만나면 그 선언을 무시하므로, 순서만 지키면 자연스럽게 나뉩니다. 먼저 sRGB 값을 쓰고, 그 아래에 P3 값을 한 줄 더 적는 방식입니다. 구형 화면은 앞 줄을, 최신 화면은 뒷 줄을 씁니다. 코드 한 줄이 늘어날 뿐 위험 부담은 없습니다.
실무 감각으로 말하면, P3는 "전부 갈아엎을 대상"이 아니라 브랜드 컬러와 강조색에만 얹는 한 겹입니다. 본문 글자색이나 회색조까지 P3로 옮길 이유는 거의 없습니다.
그런데 지금 당장 바꿔야 할까요
정직하게 말하면, 작은 회사 홈페이지에서 P3 색역까지 가는 일은 급하지 않습니다. 손님이 "이 청록색이 원래보다 덜 선명하네" 하고 알아채는 경우는 거의 없으니까요.
하지만 oklch로 색을 관리하는 것은 지금 바꿔도 남는 장사입니다. 이유는 색이 예뻐져서가 아니라 유지보수가 쉬워지기 때문입니다.
- 브랜드 색이 바뀌었을 때, H 값 하나만 고치면 파생 색이 전부 따라옵니다
- "버튼 호버 색을 조금 어둡게"가 감이 아니라 L 값 조정으로 끝납니다
- 다크 모드 대응이 색을 새로 고르는 일이 아니라 값을 뒤집는 일이 됩니다
- 글자 대비가 부족한 조합을 눈으로 확인하기 전에 숫자로 걸러낼 수 있습니다
즉 oklch는 "더 좋은 색"이 아니라 더 다루기 쉬운 색입니다. 사이트를 만들고 끝이 아니라 몇 년 운영할 생각이라면, 이 차이가 훨씬 크게 체감됩니다.
이렇게 옮겨가면 됩니다
- 브랜드 색 몇 개만 먼저 oklch로 변환합니다. 기존 hex 값을 그대로 바꿔 적기만 해도 화면 결과는 동일합니다
- 그 색들을 CSS 변수로 묶어 한 곳에서 관리합니다. 색이 코드 곳곳에 흩어져 있으면 어떤 좌표계를 써도 소용없습니다
- 파생 색(호버, 연한 배경, 테두리)은 손으로 값을 찍지 말고 L과 C만 조정해서 뽑습니다
- 선명함이 중요한 강조색 한두 개에만 P3 줄을 추가로 얹습니다
- 바꾼 뒤에는 반드시 아이폰과 구형 윈도 노트북 양쪽에서 실제로 봅니다
결국 색은 값이 아니라 시스템입니다
저희가 사이트를 다시 손볼 때 가장 자주 마주치는 문제는 색이 촌스러운 게 아니라, 색이 관리되지 않는 상태입니다. 같은 파랑이 CSS 안에 일곱 가지 미묘하게 다른 값으로 흩어져 있고, 아무도 어느 게 진짜인지 모릅니다. 그 상태에서는 "브랜드 색 조금만 바꿔주세요"가 반나절짜리 작업이 됩니다.
oklch와 display-p3는 그 자체로 화면을 예쁘게 만들어주지 않습니다. 다만 색을 규칙으로 다룰 수 있게 해줍니다. 그리고 규칙이 있는 색은 1년 뒤에도, 담당자가 바뀐 뒤에도 무너지지 않습니다.
CYAN 에이전시는 사이트를 만들 때 색을 화면에 칠하고 끝내지 않고, 나중에 사장님이나 담당 직원이 직접 조정할 수 있는 형태로 정리해 넘겨드립니다. 지금 쓰고 계신 사이트의 색이 어디에 어떻게 박혀 있는지 아무도 모르는 상태라면, 그것부터 한번 정리해보시길 권합니다.