색상 대비
#777과 #767: 대비율 반올림이 결과를 바꾸는 순간
표시되는 색상 대비율의 반올림 표기로 인해 WCAG 2.2 AA 기준 미달 요소가 통과로 오판정되는 경계값 계산 원리와 재검사 절차를 설명합니다.
실무 검증 기록
수치·계산식 경계값 검증
본 기록은 공개 fixture와 재현 조건을 기준으로 정리한 기술 설명입니다. 실제 브라우저·스크린리더 조합의 동작은 별도 수동 검토가 필요합니다.
| 검증 상태 | 공개 fixture 및 공식 규격 대조 완료 |
|---|---|
| 검증 기준 | 공개 fixture 및 재현 조건 |
| 검증 범위 | 색상 대비 원값·반올림 표기·렌더링 픽셀 실측 및 명시된 입력값에 한정 |
| 수동 확인 | 실제 브라우저·키보드·스크린리더 환경에서 별도 확인 필요 |
| fixture에서 확인한 기대 결과 | [실패 상태] 4.5:1로 반올림되어 실패가 통과처럼 표시 ➔ [수정 목표] 원값 비교와 안전 마진을 적용한 색상 조정 |
검증에 사용된 실제 픽스처 / 재현 조건
흰색 배경 위 #777777 / #767676 / #757575 / #808080 텍스트와 색 견본- 헤드리스 Chromium 한 대, 회색 단일 채널 기준
- 서브픽셀 렌더링·얇은 폰트·저시력 사용자 체감 미측정
#777777과 #767676은 눈으로 구별하기 어려운 회색이지만 WCAG 2.2 AA(일반 텍스트 4.5:1)에서는 결과가 갈립니다. 흰 배경 기준 원값은 각각 4.478089:1과 4.542225:1이고, 소수 첫째 자리로 반올림하면 둘 다 '4.5'로 보입니다. 이 글은 두 색을 실제 Chromium에서 렌더링해 읽은 값, 이 사이트 색상 대비 엔진의 판정, 글자 가장자리 픽셀 측정을 함께 제시하고 반올림 값으로 판정하면 안 되는 이유를 정리합니다.
W3C 상대 휘도(Relative Luminance) 정밀 수학 계산식의 원리
W3C WCAG 가이드라인에서 규정한 두 색상 간의 명암비(Contrast Ratio)는 단순한 RGB 수치의 산술 평균이 아닙니다. 인간의 망막이 색상 파장별로 밝기를 느끼는 생리학적 민감도(녹색에 가장 민감하고 청색에 덜 민감함)와 디스플레이의 비선형 감마(sRGB 감마 보정) 특성을 복합적으로 반영한 선형화 상대 휘도(L, Relative Luminance) 공식을 기반으로 계산됩니다.
먼저 8비트 sRGB 색상 채널값(0~255)을 0.0~1.0 사이의 값으로 정규화(C_sRGB = C / 255)합니다. 그 후 각 채널값이 0.04045 이하이면 C_linear = C_sRGB / 12.92를 적용하고, 0.04045를 초과하면 C_linear = ((C_sRGB + 0.055) / 1.055) ^ 2.4 공식을 통해 비선형 감마를 선형화합니다. 이렇게 선형화된 R, G, B 채널값에 W3C 표준 가중치를 곱하여 상대 휘도 L = 0.2126 * R_linear + 0.7152 * G_linear + 0.0722 * B_linear를 도출합니다.
최종 명암비는 더 밝은 색상의 휘도 L1과 더 어두운 색상의 휘도 L2를 대입하여 (L1 + 0.05) / (L2 + 0.05) 공식으로 산출됩니다. 이 복잡한 계산의 결과는 무한소수로 떨어지기 마련이며, 이 소수점 아래의 미세한 차이가 표준 준수 여부를 결정짓는 분기점이 됩니다.

측정 기록: 렌더링된 색과 도구 엔진 값 비교
이 사이트의 측정 스크립트(scripts/measure-article-cases.ts)로 Chromium 153.0.8010.12, Windows, 2026-10-17 환경에서 흰색(#FFFFFF) 배경 위에 네 가지 회색을 칠하고, ① getComputedStyle 값 ② 스크린샷에서 읽은 픽셀 RGB ③ 색상 대비 엔진(contrast-1.0.0)의 판정을 비교했습니다.
- #777777: 브라우저 계산 색 rgb(119, 119, 119), 렌더 픽셀 RGB [119, 119, 119], 원값 4.478089:1, 소수 첫째 자리 표기 4.5, 엔진 판정 fail (제안 색 #767676)
- #767676: 브라우저 계산 색 rgb(118, 118, 118), 렌더 픽셀 RGB [118, 118, 118], 원값 4.542225:1, 소수 첫째 자리 표기 4.5, 엔진 판정 pass
- #757575: 브라우저 계산 색 rgb(117, 117, 117), 렌더 픽셀 RGB [117, 117, 117], 원값 4.607518:1, 소수 첫째 자리 표기 4.6, 엔진 판정 pass
- #808080: 브라우저 계산 색 rgb(128, 128, 128), 렌더 픽셀 RGB [128, 128, 128], 원값 3.949440:1, 소수 첫째 자리 표기 3.9, 엔진 판정 fail (제안 색 #767676)
측정에서 확인한 것과 확인하지 못한 것
네 색 모두에서 브라우저 계산 색, 렌더 픽셀, 엔진 계산값이 일치했습니다. 이 환경에서는 브라우저가 지정한 색을 그대로 그렸고, #777777과 #767676의 판정이 갈린 원인은 렌더링 오차가 아니라 표기 반올림뿐이었습니다. 소수 첫째 자리 값(4.5)으로 판정하면 #777777이 통과(true)로 바뀌지만, 원값으로 비교하면 실패(false)입니다. #757575(4.6075:1)는 통과, #808080(3.9494:1)은 실패였습니다.
글자 가장자리도 확인했습니다. #767676과 #777777을 12px·14px·16px(굵기 400)와 16px(굵기 700)로 렌더링한 스크린샷에서 가장 어두운 픽셀의 채널값을 읽었더니 여덟 조합 모두 지정한 색의 채널값(118, 119)과 같았습니다. 글자 획 안쪽 픽셀은 지정한 색을 유지하고, 가장자리 픽셀만 배경과 섞입니다. 이 측정 범위에서는 '체감 대비가 10~20% 떨어진다'는 주장을 확인하지 못했습니다.
다만 이 측정은 헤드리스 Chromium 한 대에서 회색 단일 채널만 읽은 결과입니다. 서브픽셀 렌더링이 켜진 실제 모니터, 얇은 폰트(굵기 300 이하), 저시력 사용자의 체감 대비는 측정하지 않았으므로 이 글은 그 부분에 대해 아무것도 주장하지 않습니다.
#777777과 #767676 헥사코드 경계값 분석과 반올림의 함정
흰색(#FFFFFF) 배경 위에서 디자이너들이 중립 회색 텍스트로 가장 널리 사용하는 16진수 코드 #777777(약칭 #777)과 #767676(약칭 #767)의 정밀 대비율을 비교해 보면 반올림 표기의 위험성이 극명하게 드러납니다.
#FFFFFF의 상대 휘도는 1.0입니다. #777777(RGB 119, 119, 119)의 선형화 휘도를 정밀 연산하면 약 0.1843이 나옵니다. 이를 공식에 대입하면 명암비는 (1.0 + 0.05) / (0.1843 + 0.05) = 1.05 / 0.2343 ≒ 4.4784:1이 산출됩니다. 이 수치는 WCAG 2.2 AA 기준인 4.50:1에 명백히 미달하는 '실패(Fail)'입니다. 그러나 소수점 둘째 자리에서 반올림하는 UI 도구는 4.478을 4.5로 올려 표시하므로, 실무자는 기준을 통과한 것으로 착각하게 됩니다.
반면 텍스트 색상을 단 한 단계 어둡게 조정한 #767676(RGB 118, 118, 118)의 선형화 휘도는 약 0.1809이며, 최종 명암비는 1.05 / 0.2309 ≒ 4.5422:1이 됩니다. 이 수치는 4.50:1을 확실하게 상회하므로 온전한 '합격(Pass)'입니다. 16진수 코드의 단 1단계 차이(#77에서 #76)가 법적 접근성 기준의 합격과 불합격을 가르는 결정적인 경계선이 됩니다.
계산값만으로 남는 불확실성과 안전 마진을 두는 이유
계산식은 지정한 색 두 개만 입력으로 받습니다. 모니터 패널 특성, 색공간, 서브픽셀 렌더링, 얇은 폰트처럼 실제 화면에서 달라질 수 있는 요소는 계산에 들어가지 않습니다. 위 측정에서 확인한 것은 '한 환경에서 지정 색이 그대로 렌더링된다'는 사실까지입니다.
그래서 디자인 시스템에서는 법적 최소치(4.50:1) 바로 위의 색을 쓰지 않고 4.6:1 안팎의 여유를 두는 방법을 고려할 수 있습니다. 이는 WCAG가 요구하는 사항이 아니라 이 사이트가 제안하는 운영 방식입니다. 예를 들어 #757575(4.61:1)는 #767676(4.54:1)보다 조금 더 여유가 있습니다.
실무 검증 루틴 및 CI/CD 자동화 체크포인트
경계값 오판정으로 인한 재감사 불합격을 원천 방지하기 위해 다음 3단계 검증 프로세스를 프로젝트에 도입할 것을 권장합니다.
1단계: UI 표기값 의심하기. 검사 도구 화면에 4.4:1 ~ 4.6:1 사이의 아슬아슬한 수치가 표시되는 모든 색상 조합을 '위험 경계군'으로 별도 태깅합니다.
2단계: 부동소수점 정밀 계산기 검증. W3C 공식 Contrast Checker 또는 Colour Contrast Analyser(CCA) 도구를 사용하여 소수점 둘째 자리(4.50:1)까지 수치를 확인하고, 4.499:1 이하인 항목은 가차 없이 수정 대상으로 분류합니다.
3단계: 배포 파이프라인(CI/CD) 자동 차단. 단위 테스트(Unit Test) 코드에서 색상 코드를 선형화하여 검증할 때, Math.round()를 거친 값이 아니라 순수 원값(Floating point)이 4.50 이상인지를 검증하는 단언문(expect(ratio).toBeGreaterThanOrEqual(4.50))을 의무화합니다.
수치 경계값 판정 기준표
| 수치 조건 | 연산 부하 | 판정 위험 | 권장 조치 |
|---|---|---|---|
| 반올림 표기 4.5:1 수치를 그대로 인정하고 조치 없음 | 낮음 (0분) | 높음 (정밀 심사 시 WCAG 2.2 SC 1.4.3 불합격 판정) | 비권장 |
| 소수점 둘째 자리 정밀 재검사 후 4.50:1 미달 시 색상 조정 | 중간 (5분) | 낮음 (정확한 표준 준수 및 오판정 위험 제거) | 적극 권장 |
| 디자인 시스템 기본 최소 대비율을 4.6:1 이상으로 규정 | 중간 (디자인 시스템 반영) | 매우 낮음 (렌더링 환경 변화에 대한 충분한 안전지대 확보) | 최적의 표준 전략 |
재검사 절차 및 안전 마진 확보 가이드
- 현재 사용 중인 색상 대비 검사 도구의 소수점 반올림 표기 여부를 확인합니다.
- 4.4:1~4.6:1 표기 구간에 해당하는 텍스트 요소의 헥사 코드를 수집합니다.
- W3C 상대 휘도 정밀 계산식 기준으로 4.50:1 미만인 요소를 #767676 이하의 더 어두운 색상으로 변경합니다.
소수점 연산 및 브라우저 렌더링 한계
- 폰트 굵기 700 이상이어도 14pt(18.66px) 미만이면 대형 텍스트 기준(3:1)이 아니라 일반 텍스트 기준(4.5:1)이 적용됩니다.
- 측정은 헤드리스 Chromium 한 대의 회색 단일 채널 값입니다. 서브픽셀 렌더링, 얇은 폰트, 실제 모니터와 저시력 사용자의 체감은 측정하지 않았습니다.
- 배경 이미지·그라디언트처럼 단색이 아닌 배경은 이 측정과 엔진 판정의 범위 밖입니다.