색을 숫자로
"조금 더 밝은 초록으로 해 주세요." 이 부탁을 받은 사람이 열 명이면 초록도 열 가지가 나온다. 그래서 디지털 도구는 색을 숫자로 적는다. 그런데 숫자에도 여러 방언이 있다. 같은 초록이 #2f7d5b이기도 하고, hsl(154 45% 34%)이기도 하고, oklch(53.2% 0.094 162)이기도 하다. 어떤 방언은 화면이 빛을 내는 방식에 맞춰져 있고, 어떤 방언은 사람이 색을 느끼는 방식에 맞춰져 있다. 이 장은 그 차이가 실제 작업에서 어떤 결과를 내는지 본다.
- RGB와 hex가 화면의 빨강·초록·파랑 빛의 세기를 적은 것임을 안다.
- 화면의 숫자가 빛의 양에 비례하지 않는다는 것(감마)과, 그래서 "숫자의 평균"과 "빛의 평균"이 다르다는 것을 확인한다.
- HSL로 만든 명도 단계가 고르지 않고 색상까지 흔들리는 이유를 본다.
- CIELAB과 OKLCH 같은 지각 균일 색 공간에서 색을 고르고 단계를 만든다.
- 색역의 뜻과 sRGB·Display P3의 차이를 알고, 같은 숫자가 화면마다 다르게 보이는 이유를 설명한다.
이름 대신 숫자
2장에서 본 것처럼 눈은 빛을 세 개의 숫자로 줄여서 본다. 그러니 색을 적는 데도 숫자 세 개면 충분하다. 문제는 어떤 세 숫자를 쓰느냐다. 가장 흔한 것은 화면이 내는 빨강(R)·초록(G)·파랑(B) 빛의 세기를 그대로 적는 RGB(Red, Green, Blue)다. 각 값은 0~255의 정수로 적고, 웹과 디자인 도구는 이를 16진수 두 자리씩 붙인 hex 코드(Hex code)로 쓴다.
#2f7d5b는 빨강 47, 초록 125, 파랑 91을 뜻한다. 1장에서 서윤이 고른 로고 초록 후보다. 숫자 세 개가 각각 화면의 빨강·초록·파랑 화소를 얼마나 켤지를 정한다.RGB의 세 값을 세 축으로 놓으면 모든 화면 색은 한 변이 255인 정육면체 안에 들어간다. 한 모서리는 검정, 맞은편 모서리는 흰색이고, 나머지 여섯 모서리가 빨강·초록·파랑과 그 둘씩의 섞임(노랑·청록·마젠타)이다. 아래는 파랑 값을 하나로 정하고 그 정육면체를 자른 단면이다. 손잡이를 끌어 색을 고르고, 슬라이더로 단면의 높이를 바꾼다.
RGB 정육면체의 한 단면
#2f7d5b(빨강 47, 초록 125)를 찾는다. ② "같은 명도끼리 선으로 잇기"를 켠다. 같은 밝기로 느껴지는 색들을 이은 선이 축과 나란하지 않고 비스듬하며, 초록 쪽으로 기울어 있다. 초록 값 10을 올리는 것은 빨강 값 10을 올리는 것보다 훨씬 밝아지고, 파랑 10은 거의 표가 나지 않는다. ③ 파랑을 0과 255로 끝까지 민다. 파랑 값이 255나 바뀌는 동안 명도 L*는 생각보다 적게 변한다. 숫자 하나하나가 사람의 감각에 대응하지 않는다는 뜻이다. (L*는 CIELAB 명도, 0 = 검정, 100 = 흰색. 화면 색은 기기마다 다르므로 같은 값이라도 기기에 따라 조금씩 다르게 보인다.)RGB는 화면에 일을 시키기에는 완벽한 숫자다. 화면은 정확히 그 세 빛을 켜는 기계이기 때문이다. 그러나 사람에게 묻는 질문, "이 색은 얼마나 밝은가", "얼마나 선명한가", "무슨 색 계열인가"에는 RGB의 세 숫자 중 어느 것도 직접 대답하지 않는다. 이 장의 나머지는 그 질문에 대답하는 숫자를 찾아가는 길이다. 그 전에 RGB 숫자에 숨은 함정 하나를 먼저 본다.
화면의 숫자는 빛의 양이 아니다
RGB 값 128은 255의 거의 절반이다. 그렇다면 128로 칠한 회색은 흰색의 절반만큼 빛을 낼까. 그렇지 않다. 화면은 숫자를 그대로 빛으로 바꾸지 않고, 정해진 곡선을 거쳐 바꾼다. 128은 흰색의 약 22%의 빛만 낸다. 이 곡선을 감마(Gamma, 전달 함수)라고 부른다. 웹과 대부분의 화면이 따르는 sRGB 표준(IEC 61966-2-1)의 곡선은 다음과 같다.
왜 이렇게 했을까. 사람의 눈은 어두운 쪽의 작은 차이에 훨씬 민감하다. 빛의 양을 그대로 0~255로 나누면 어두운 쪽 계단이 눈에 띄게 거칠고 밝은 쪽 계단은 낭비된다. 감마 곡선은 숫자를 어두운 쪽에 더 촘촘히 배정해서, 255단계로 사람 눈에 고르게 보이는 계단을 만든다. 숫자는 대략 "느끼는 밝기"에 가깝게, 빛은 그 곡선을 거쳐 나온다. 직접 확인해 본다. 왼쪽은 검정과 흰색 줄을 한 줄씩 번갈아 그은 칸이고, 오른쪽은 한 가지 회색이다. 줄무늬 칸은 정확히 흰빛의 50%를 낸다.
줄무늬의 회색은 몇일까
이 차이는 색을 섞을 때 문제가 된다. 사진을 줄이거나 흐리게 할 때, 점묘화를 멀리서 볼 때, 빛은 빛의 양끼리 섞인다. 그런데 프로그램이 화면 숫자를 그대로 평균하면 실제보다 어둡고 탁한 결과가 나온다. 1장의 점묘 시뮬레이터에서 "숫자를 그대로 평균"을 켰을 때 본 그 현상이다. 반대로 "보기에 고른 그라데이션"을 만들 때는 빛의 평균이 오히려 밝은 쪽으로 치우친다. 두 색 사이를 잇는 방법이 여러 가지라는 뜻이다.
아래는 같은 두 색을 네 가지 방법으로 이은 띠다. "숫자 평균"은 RGB 숫자를 그대로 섞고, "빛 평균"은 감마를 풀어 빛의 양으로 섞고, "OKLab"과 "OKLCH"는 다음 절들에서 만날 지각 균일 공간에서 섞는다. 아래 그래프는 띠를 따라가며 잰 명도 L*다.
두 색 사이의 네 갈래 길
linear-gradient(in oklch, …)처럼 섞는 공간을 지정하는 문법을 정의했고, 최신 브라우저가 지원한다. 화가의 습관과도 같다. 수채화에서 보색 두 색을 번지기로 이으면 가운데가 탁해지므로, 화가들은 이웃한 색을 거쳐 가도록 중간 색을 따로 칠한다.
HSL: 편리하지만 고르지 않은 원통
RGB로는 "조금 더 밝게"를 말하기 어렵다. 그래서 1978년 앨비 레이 스미스(Alvy Ray Smith)는 RGB 정육면체를 원통 모양으로 다시 배치한 HSV를 발표했고, 비슷한 HSL도 널리 쓰이게 되었다. HSL(Hue, Saturation, Lightness)은 색상 H(색상환 위의 각도, 0~360°), 채도 S(0~100%), 명도 L(0~100%)로 색을 적는다. 디자인 도구의 색 선택기에서 흔히 보는 HSB·HSV도 같은 집안이다. 이름만 보면 사람의 언어와 꼭 맞는다.
1장에서 HSL 명도 50%의 열두 색이 실제로는 L* 30에서 97까지 벌어지는 것을 봤다. 이번에는 한 색상 안에서 명도 단계를 만들어 본다. 버튼, 배경, 테두리, 글자처럼 같은 계열의 색을 여러 밝기로 쓰는 일은 UI 디자인에서 매일 한다. 윗줄은 HSL의 L을 같은 간격으로 올린 단계, 아랫줄은 같은 두 끝 사이를 OKLCH의 명도로 같은 간격으로 나눈 단계다. 칸 아래 막대는 이웃한 두 칸의 명도(L*) 차이다.
HSL 계단과 OKLCH 계단
HSL이 고르지 않은 이유는 간단하다. HSL의 L은 RGB 세 값 중 가장 큰 값과 가장 작은 값의 평균일 뿐이다. 감마로 인코딩된 숫자의 평균이고, 초록이 파랑보다 훨씬 밝게 느껴진다는 사실(2장의 \(\bar y\) 곡선)을 전혀 모른다. HSL은 RGB를 사람이 다루기 쉽게 배치한 좌표이지, 사람의 감각을 잰 좌표가 아니다. 빠르게 색을 고를 때는 충분히 편리하다. 문제는 그 숫자로 "같은 간격"이나 "같은 밝기"를 만들려 할 때 생긴다.
눈에 맞춘 공간: Lab과 OKLCH
"숫자의 차이가 눈으로 느끼는 차이와 비슷하도록" 만든 색 공간을 지각 균일 색 공간(Perceptually uniform color space)이라고 한다. 이 생각을 처음 체계로 만든 사람은 공학자가 아니라 화가였다. 미국의 화가이자 미술 교사 앨버트 먼셀(Albert H. Munsell, 1858–1918)은 색상·명도·채도의 세 축을 정하고, 이웃한 견본끼리의 차이가 눈으로 보기에 같아지도록 색표를 만들었다(1905년 『색 표기법』(A Color Notation)). 먼셀 표기법은 지금도 토양·식품 색 판정과 여러 나라의 산업 표준에 쓰인다.
국제조명위원회는 1976년 계산으로 구할 수 있는 지각 균일 공간 CIELAB(L*a*b*)을 정했다. L*는 명도(0~100), a*는 초록(−)에서 빨강(+)으로, b*는 파랑(−)에서 노랑(+)으로 가는 축이다. 2장 끝에서 본 반대색 신호(밝기, 빨강–초록, 노랑–파랑)와 같은 짜임이다. 이것을 원통 좌표로 바꾼 것이 LCh다. 2020년 비에른 오토손(Björn Ottosson)은 같은 짜임으로 색상이 더 고르게 유지되도록 다시 맞춘 OKLab과 그 원통 좌표 OKLCH를 발표했고, CSS Color 4가 이를 oklch() 함수로 받아들였다.
OKLCH의 C와 h는 OKLab의 두 가로축 a, b에서 바로 나온다.
#2f7d5b는 OKLab으로 \(L=0.532,\ a=-0.089,\ b=0.030\)이고, OKLCH로 \(L=0.532,\ C=0.094,\ h=162°\)다.OKLCH의 장점은 세 숫자가 서로 간섭하지 않는다는 데 있다. 명도만 바꾸면 색상이 따라 흔들리지 않고, 색상만 바꾸면 밝기가 따라 출렁이지 않는다(완벽하지는 않지만 HSL보다 훨씬 낫다). 아래 그림은 한 색상(h)에서 OKLCH 공간을 세로로 자른 단면이다. 세로가 명도 L, 가로가 채도 C다. 빗금 친 곳은 화면(sRGB)이 낼 수 없는 색이다. 손잡이를 끌어 색을 고르고, 슬라이더로 색상을 돌린다.
OKLCH 단면에서 고르기
색역: 화면이 낼 수 있는 색
앞의 단면에서 빗금 친 영역은 사람이 볼 수 있지만 화면이 낼 수 없는 색이다. 화면이 낼 수 있는 색의 범위를 색역(Gamut)이라고 한다. 색역은 화면의 세 원색(가장 선명한 빨강·초록·파랑 화소)이 정한다. 세 원색을 섞어서 만들 수 있는 색만 낼 수 있기 때문이다. 2장의 색 맞추기에서 청록 단색광을 세 빛으로 맞출 수 없었던 것과 같은 이유다.
색역을 한눈에 비교하려고 국제조명위원회의 xy 색도도(Chromaticity diagram)를 쓴다. 밝기를 빼고 "어떤 색인가"만 평면에 펼친 지도다. 말굽 모양의 바깥 테두리는 2장의 단색광들이 놓이는 자리이고, 사람이 볼 수 있는 모든 색은 그 안에 있다. 화면의 색역은 세 원색을 꼭짓점으로 하는 삼각형이 된다. 웹의 표준인 sRGB와, 요즘 휴대폰·노트북에 많이 쓰이는 더 넓은 Display P3를 비교한다.
sRGB 삼각형과 P3 삼각형
#2f7d5b를 P3의 원색으로 해석하면 점이 테두리 쪽으로 밀려난다. 1장에서 휴대폰 화면의 초록이 더 선명하게 보였던 한 가지 설명이다. (말굽 안의 색은 화면이 낼 수 있는 범위로 줄여 그린 것이라 실제 색보다 탁하다. 테두리는 이 책의 엔진이 쓰는 CIE 1931 등색 함수 근사로 그렸다.)휴대폰이 더 선명하게 보인 이유를 정리하면 이렇다. 파일에 적힌 #2f7d5b는 "sRGB의 원색으로 빨강 47, 초록 125, 파랑 91"이라는 뜻이다. 색 관리가 제대로 되는 프로그램은 P3 화면에 보내기 전에 이 값을 P3의 숫자(약 69, 123, 93)로 바꿔서 같은 색을 낸다. 그런데 색 관리가 빠진 경로(색 정보가 없는 이미지, 일부 앱이나 설정)에서는 47, 125, 91을 그대로 P3 화소에 보낸다. P3의 초록 화소는 sRGB의 초록보다 선명하므로 같은 숫자가 더 선명한 색이 된다. 이 책의 모델로 계산하면 채도가 0.094에서 0.120으로 약 28% 올라가고, 색상이 162°에서 165°로 조금 푸르게 옮겨 간다. 서윤이 본 "더 선명하고 푸르게"와 같은 방향이다.
지금 보고 있는 화면이 P3를 낼 수 있는지 바로 확인할 수 있다. 아래 두 칸은 CSS로 칠했다. 왼쪽은 sRGB가 낼 수 있는 가장 선명한 초록(#00ff00), 오른쪽은 P3의 가장 선명한 초록(color(display-p3 0 1 0))이다. P3 화면에서는 오른쪽이 확실히 더 진하고 형광에 가깝다. sRGB 화면에서는 브라우저가 오른쪽을 낼 수 있는 만큼으로 줄여서 두 칸이 같아 보인다.
#00ff00
P3 가장 선명한 초록display-p3 0 1 0
sRGB 가장 선명한 빨강#ff0000
P3 가장 선명한 빨강display-p3 1 0 0
숫자로 일하기
그렇다면 어떤 숫자를 써야 할까. 이 책의 권장은 역할을 나누는 것이다. 기록과 설계는 OKLCH로 한다. 명도 단계, 채도 조절, 색상 돌리기가 모두 한 숫자만 바꾸면 되고, 그 결과가 눈의 감각과 비슷하다. 전달과 실행은 그 숫자에서 파생한 hex나 RGB로 한다. 많은 도구와 인쇄소가 아직 hex를 기준으로 일하기 때문이다. 그리고 섞기, 흐리게 하기, 이미지 줄이기처럼 빛이 실제로 합쳐지는 계산은 감마를 푼 선형 빛으로 한다.
| 숫자 | 잘하는 일 | 조심할 일 |
|---|---|---|
| hex · RGB | 화면에 정확히 무엇을 켤지 전달. 도구 사이에 값 옮기기 | 밝기·채도를 숫자로 조절하기 어렵다. 숫자 평균은 빛의 평균이 아니다 |
| HSL · HSV | 색상환에서 빠르게 고르기 | 같은 L이 같은 밝기가 아니다. 명도 단계가 고르지 않고 색상이 흔들린다 |
| CIELAB · LCh | 색차 재기(ΔE), 인쇄·측색 분야의 표준 언어 | 파랑 근처의 색상 왜곡. 백색점을 함께 적어야 한다 |
| OKLCH | 단계·팔레트 설계, 브랜드 색 기록. CSS에서 바로 쓴다 | 색역 밖 값을 쉽게 만든다. 실제로 낼 수 있는지 함께 확인한다 |
| 선형 RGB | 빛 섞기, 흐림, 이미지 축소, 3D 조명 계산 | 사람이 읽고 고르기에는 맞지 않는다 |
oklch(53.2% 0.094 162)), 둘째 줄에 파생 값(#2f7d5b, 필요하면 인쇄용 값), 셋째 줄에 확인 조건(어느 화면, 어느 조명, 무엇 옆에서 봤는지). 1장에서 서윤이 정한 "값과 놓일 자리·옆의 색·조명을 함께 적는다"는 원칙을 숫자의 형식으로 옮긴 것이다. 값을 바꿀 때는 설계 값을 고치고 파생 값을 다시 계산한다. 반대로 hex만 손으로 조금씩 고치다 보면, 어느 것이 원래 의도였는지 잃어버리기 쉽다.
색 하나를 기록하는 카드
마지막 시뮬레이터는 이 장의 도구를 한 장의 카드에 모은다. 세 슬라이더는 OKLCH의 세 숫자다. 카드는 그 색을 여러 방언(hex, HSL, CIELAB, Display P3)으로 옮겨 적고, 흰 웹 배경·크라프트지 간판·검은 에코백 위에 놓아 보고, 같은 색상의 명도 단계를 만들고, sRGB와 P3에서 낼 수 있는 채도의 한계를 보여 준다. 기본값은 서윤의 로고 초록 후보다.
로고 초록 기록 카드
oklch()로 직접 칠한 칸. P3 화면이면 sRGB 밖의 색도 그대로 보인다.같은 색이 다섯 가지 방언으로 적혔다. 그중 어느 것도 틀리지 않았다. 다만 OKLCH의 세 숫자만이 "조금 더 밝게", "조금 덜 선명하게", "조금 더 푸르게"라는 사람의 말에 한 숫자씩 대응한다. 1장의 질문 "조금 더 밝은 초록으로 해 주세요"는 이제 "L을 0.05 올려 주세요"가 된다.
서윤의 작업 노트
고르게 올렸는데 고르게 밝아지지 않았다
서윤은 책방 E 웹사이트의 초록 단계를 HSL로 만들었다. 로고 초록 #2f7d5b는 HSL로 색상 154°, 채도 45%, 명도 34%다. 색상과 채도는 그대로 두고 명도만 15%에서 95%까지 10%씩 올려 아홉 단계를 만들었다. 숫자로는 완벽하게 고른 계단이었다. 그런데 화면에 놓고 보니 어두운 세 칸은 서로 너무 달랐고, 밝은 네 칸(테두리·배경용)은 서로 거의 구별되지 않았다. 밝은 칸일수록 초록이 아니라 민트색으로 푸르게 기울었다.
이 책의 모델로 재 보니 HSL 계단의 명도(L*)는 20.5, 35.1, 48.7, 61.7, 70.9, 77.0, 83.4, 90.0, 96.6이었다. 이웃 간격이 어두운 쪽에서는 14.6, 밝은 쪽에서는 6.4~6.6으로 두 배 넘게 차이가 났고, OKLCH 색상은 161°에서 168°까지 흔들렸다. 서윤은 같은 아홉 단계를 OKLCH로 다시 만들었다. 색상 162°를 고정하고 명도를 0.30에서 0.96까지 같은 간격으로 나누고, 채도는 0.094를 넘지 않되 그 명도에서 낼 수 있는 만큼만 쓰게 했다. 새 계단의 L* 간격은 9.1~9.8로 고르다.
한도경은 서윤의 화면을 보더니 자기 색 일지의 한 쪽을 펼쳤다. 젊을 때 물감으로 칠한 회색 9단계였다. "나는 이걸 눈으로 맞췄어. 숫자로 고른 너의 첫 번째 계단보다, 다시 만든 계단이랑 더 비슷하네." 서윤은 먼셀이 화가였다는 이야기를 해 주었고, 도경은 그 대가로 서윤에게 휴대폰 사진을 흑백으로 바꿔 계단을 확인하는 법을 배웠다. 마지막으로 서윤은 1장의 수수께끼 하나를 풀었다. 휴대폰 화면은 Display P3였고, 같은 숫자를 색 관리 없이 P3로 읽으면 채도가 0.094에서 0.120으로 올라간다. 휴대폰의 "더 선명한 초록"은 다른 색이 아니라 다른 방언으로 읽힌 같은 숫자였다.
oklch(53.2% 0.094 162), 파생 값 #2f7d5b(sRGB 안), L* 47.0, 흰 바탕 대비 4.99. 웹의 초록 단계는 OKLCH 명도 0.30~0.96, 색상 162°의 아홉 단계로 다시 만든다.핵심 정리
- RGB와 hex는 화면의 빨강·초록·파랑 빛을 얼마나 켤지 적은 숫자다. 화면에 일을 시키기에는 정확하지만, 밝기·선명함·색 계열을 직접 말해 주지 않는다.
- 화면 숫자는 감마 곡선을 거쳐 빛이 된다. 128은 흰빛의 약 22%, 빛의 절반은 188이다. 빛이 실제로 섞이는 계산(흐림, 축소, 점묘)은 감마를 푼 선형 빛으로 한다.
- HSL은 RGB를 원통으로 배치한 것이다. 같은 L이 같은 밝기가 아니고, L을 같은 간격으로 올려도 명도 단계가 고르지 않으며 색상이 흔들린다.
- CIELAB과 OKLCH는 숫자의 차이가 눈의 차이와 비슷하도록 만든 지각 균일 공간이다. OKLCH의 L·C·h는 명도·채도·색상에 하나씩 대응한다.
- 색역은 화면의 세 원색이 정하는 범위다. Display P3는 sRGB보다 넓어서, 색 관리가 빠지면 같은 숫자가 더 선명하게 보인다.
- 숫자로 적을 수 있는 색이 모두 화면에 있는 것은 아니다. 색역 밖의 색은 명도와 색상을 지키며 채도를 줄여 보여 준다.
- 브랜드 색은 OKLCH로 설계·기록하고, hex는 그 파생값으로, 확인 조건(화면·조명·바탕)을 함께 적는다.
확인 퀴즈
1. HSL로 명도 L을 15%부터 95%까지 10%씩 올려 초록 아홉 단계를 만들었더니 밝은 쪽 칸들이 서로 거의 구별되지 않았다. 가장 알맞은 설명은?
2. 고운 흑백 줄무늬 사진을 프로그램으로 절반 크기로 줄였더니 원래보다 어두운 회색이 되었다. 무엇이 잘못되었나?
3. 같은 이미지 파일의 초록이 노트북보다 휴대폰에서 더 선명하게 보였다. 휴대폰은 Display P3 화면이다. 가장 그럴듯한 설명은?
4. 서윤이 브랜드 색을 oklch(53.2% 0.094 162)로 기록하고 hex는 파생값으로 두기로 했다. 그 이유로 가장 알맞은 것은?