브랜드 컬러를 최대한 유지하면서 WCAG 통과시키기

color-mix, oklch, ΔE로 접근성을 지켜낸 색 variant 설계 기록

Featured image

들어가며

브랜드 컬러는 못 바꾼다는데 WCAG는 맞춰야 했다.

디자인은 이미 확정되어 있었고, 색 또한 브랜드 가이드에 따라 정해져 있었습니다. 화면에서는 충분히 보기 좋아 보였지만, 대비(contrast) 비율을 계산해보니 WCAG 기준에 미달하는 경우가 있었습니다. 색을 완전히 변경할 수는 없었고, 그렇다고 접근성 기준을 무시할 수도 없는 상황이었습니다.

프론트엔드에서 색은 단순히 화면을 꾸미는 요소라고 생각했던 적도 있었습니다. 하지만 실제로는 텍스트가 읽히는지, 상태가 명확히 구분되는지, 정보가 제대로 전달되는지를 좌우하는 기능적 요소에 가까웠습니다. 특히 이미 정해진 색 체계 안에서 작업해야 할 때는, 감각보다는 기준과 계산이 더 중요하다는 점을 체감하게 되었습니다.

이 글은 “예쁜 색을 고르는 방법”에 대한 이야기가 아닙니다. 제한된 조건 안에서 WCAG 대비 기준을 만족시키기 위해 색의 variant를 설계했던 경험을 정리한 글입니다. 그 과정에서 color-mix()oklch 색좌표계를 활용해 기존 색과 최대한 유사한 색을 만들어보았고, 단순히 눈으로 비슷해 보이는 수준이 아니라 실제로 얼마나 차이가 나는지를 ΔE(Delta E) 거리로 확인해보기도 했습니다.

접근성을 지키면서도 브랜드 아이덴티티를 훼손하지 않기 위해 어떤 기준과 도구를 사용했는지, 그리고 그 과정에서 무엇을 고려해야 했는지를 차근히 정리해보려 합니다.

WCAG(접근성 기준) 에서의 색 기준

FE 개발을 하는 사람으로서, ‘접근성’ 이라는 것을 들어보지 않기 힘들것 입니다. 웹 접근성에는 여러가지가 있으나, 이번 글에서 중점적으로 다룰 항목은, 색 대비에 대한 항목 입니다.

간단히 요약하자면 텍스트나, 텍스트 이미지는 그 배경과 4.5:1, 특정 기준을 만족하는 큰 글씨의 경우에는 3:1의 색 대비를 만족해야 하는 기준입니다.

하지만, 현실의 문제는 이상적이지 않다

제가 마주한 문제는 당시에 이미 퍼블리싱 되어 배포된 프로젝트에 대해서 작업을 하였고, 기존의 색을 ‘최대한 덜’건드리는 선에서 WCAG의 배경색 기준을 만족했어야만 하였습니다.

그렇기 때문에, 단순히 ‘인간의 눈으로 보기에 비슷한’ 색으로 직관에 의한 추론이 아닌, 색에 관한 이론에 기반해서 움직였어야 했습니다. 정말로 타당한 공학적인 사고를 해야하는 것 이지요.

이 글에서 다룰 색에 대한 CSS 기능

색의 모든것을 다루기에는 이 지면이 적절하지 않고, 저의 지식의 양도 적절하지 않습니다. 이번 섹션에서는 단순 명도를 조정하는데에 ‘검은색을 덧대기 위해’ 사용한 color-mix 함수와, ‘색 자체의 명도를 조정하기 위한’ oklch 색 좌표 함수입니다.

색을 섞는다. color-mix

색을 다루는 만큼, 학창시절 물감을 썼던 미술시간의 기억을 잠깐 데려와 봅시다. 그때 썼던 물감은 본격 전문가 용이 아니어서, ‘좀 더 어두운 색’을 만들기 위해서, 원본 색에 검은색 물감을 좀 더 섞고 했던 기억이 있을 것 입니다.

수채화 작업시간의 컨셉을 디지털 그래픽으로 옮긴 것이 color-mix 입니다. color-mix는 아래와 같은 문법으로 동작합니다.

color-mix( <color-interpolation-method>, <color> [<percentage>], <color> [<percentage>] )

color-interpolation-method는 어떤 기준으로 색을 다룰 것이냐(hsl, srgb, lab등)을 다루고, 뒤에 있는것은, 미술시간에 했던 그것과 동일합니다. A와 B색을 각각 몇퍼센트로 섞은 색을 만들 것이냐 이지요.

색이 어두워진다/밝아진다 라는 결과물은 얻을 수 있지만, 실제로 색을 섞어보시면 아시겠지만, 이 방법은 본래의 hue를 점점 검은색으로/흰색으로 변질시키기에, 원본의 색감과 달라지는 문제를 안게 됩니다.

색의 명도를 조절하기 위한 oklch()

oklch()는 OKLab 기반의 지각(perceptual) 색 공간에서 색을 다루는 CSS 함수입니다. 기존의 hsl()이나 rgb()가 기계적인 수치 보간에 가깝다면, OKLCH는 “사람이 느끼는 밝기”를 기준으로 설계된 색 공간입니다.

문법은 다음과 같습니다.

oklch(L C H)

핵심은 명도(L)를 독립적으로 조절할 수 있다는 점입니다.
즉, hue와 chroma를 유지한 채 “밝기만” 조절하는 것이 가능합니다.

디자인 시스템에서 100~900 스케일 만들기

예를 들어, 브랜드의 기본 색이 다음과 같다고 가정해봅시다.

:root {
  --some-color-500: oklch(0.62 0.18 250);
}

여기서 500을 기준으로, 명도만 조절해 100~900 스케일을 만들 수 있습니다.

:root {
  --some-color-100: oklch(0.92 0.18 250);
  --some-color-200: oklch(0.85 0.18 250);
  --some-color-300: oklch(0.75 0.18 250);
  --some-color-400: oklch(0.68 0.18 250);

  --some-color-500: oklch(0.62 0.18 250);

  --some-color-600: oklch(0.55 0.18 250);
  --some-color-700: oklch(0.48 0.18 250);
  --some-color-800: oklch(0.4 0.18 250);
  --some-color-900: oklch(0.32 0.18 250);
}

여기서 중요한 점은:

이렇게 하면 색감은 동일한 계열을 유지하면서도, 일관된 명도 스케일을 만들 수 있습니다.
HSL에서 lightness를 줄이는 것과 달리, OKLCH는 지각적으로 더 균일한 결과를 제공합니다.

기존 브랜드 색을 조금 더 어둡게 만들기

예를 들어 기존 브랜드 색이 다음과 같다고 가정해봅시다.

--brand-color: oklch(0.62 0.18 250);

WCAG 대비가 4.5:1에 미달하여 약간 더 어둡게 만들어야 한다면:

--brand-color-accessible: oklch(from var(--brand-color) 0.58 c h);

이 경우:

이 방식은 color-mix()로 검은색을 섞는 것보다 원본 색의 성격을 더 잘 보존합니다.
검은색을 섞는 경우 hue가 미묘하게 틀어질 수 있지만, OKLCH에서는 그 문제가 거의 발생하지 않습니다.

기존 브랜드 색을 조금 더 밝게 만들기

반대로 배경 위에서 더 눈에 띄도록 밝게 만들어야 한다면:

--brand-color-light: oklch(from var(--brand-color) 0.68 c h);

이렇게 L 값을 소폭 증가시키는 것만으로, 같은 색 계열 안에서 자연스럽게 밝은 variant를 만들 수 있습니다.

왜 OKLCH가 유리한가?

HSL에서 lightness를 조절하면 채도 체감이 함께 변하는 문제가 있습니다.
반면 OKLCH는 다음과 같은 장점이 있습니다.

  1. 지각적으로 균일한 명도 변화
  2. hue 왜곡이 적음
  3. 디자인 시스템 스케일 설계에 적합

특히 접근성 대응에서 “조금만 어둡게” 또는 “조금만 밝게” 조정해야 할 때, OKLCH는 감각이 아닌 수치 기반 조정이 가능하다는 점에서 매우 유용했습니다.

번외편 - 색거리를 측정하기 위한 ΔE

접근성 관련 작업 외에도, 디자인 시스템을 엄격하게 지키지 않고, 일단 빠르게 구현을 하기 위해서 만들어진 백오피스 시스템에 대해서도 작업했어야 했습니다. 작업을 해둔 전임자의 의도를 바로 알 수 없기 때문에, 기존 팔레트의 색과 ‘비슷’ 하면, 색을 통합하고, 차이가 좀 있다 하면, variant로서 추가하는 식이지요.

‘비슷’의 기준은 무엇이 되어야 할까요? 엔지니어 답게, ‘직감’으로가 아닌, 명확한 기준이 있어야 할 것이고 그것이 ΔE라는 개념입니다.

ΔE(Delta E)는 두 색 사이의 지각적 거리(perceptual difference)를 수치로 표현한 값입니다.
단순히 RGB 값의 차이를 계산하는 것이 아니라, 사람이 실제로 느끼는 색 차이를 기준으로 계산합니다.

ΔE는 어떻게 해석할까?

대표적으로 많이 쓰이는 기준(CIEDE2000 기준)은 다음과 같습니다.

즉, 디자인 시스템에서 “같은 계열로 묶어도 되는가?”를 판단할 때
ΔE 값은 꽤 유용한 객관적 기준이 됩니다.

실제 활용 예시

예를 들어 기존 시스템에 아래 두 색이 있다고 가정해봅시다.

이 두 색은 명도만 0.04 차이가 나므로, RGB로 변환하면 수치 차이는 꽤 커 보일 수 있습니다.
하지만 ΔE(CIEDE2000) 기준으로 계산해보면, 값이 3 이하라면 실사용자 입장에서는 “거의 같은 색 계열”로 인식될 가능성이 높습니다.

반대로, hue가 몇 도만 틀어져도 ΔE는 급격히 커질 수 있습니다.
이때는 명도 조정이 아니라 색상 왜곡이 발생한 것이므로, 단순 variant가 아니라 새로운 색으로 분리하는 것이 타당합니다.

왜 ΔE까지 고려했는가?

접근성 문제를 해결하기 위해 색을 수정할 때, 우리는 두 가지를 동시에 만족해야 했습니다.

  1. WCAG 대비 기준 충족
  2. 기존 브랜드 색과의 거리 최소화

대비 비율은 4.5:1이라는 명확한 숫자가 있습니다.
하지만 “얼마나 비슷해야 브랜드를 훼손하지 않는가?”에는 기준이 없습니다.

이 지점에서 ΔE는 훌륭한 판단 도구가 됩니다.

이러한 질문을 통해, 감각이 아니라 수치 기반 의사결정을 할 수 있게 됩니다.

결론

색을 다루는 작업은 종종 감각의 영역처럼 보이지만,
프론트엔드에서의 색은 기능적 요소이기도 합니다.

결국 이 작업은 단순히 색을 조금 바꾸는 일이 아니라,
제한된 조건 안에서 여러 기준을 동시에 만족시키는 설계 문제에 가까웠습니다.

끝까지 읽어주셔서 감사합니다.