색 대비비는 눈으로 판단할 수 없다
회색 767676은 통과하고 777777은 실패합니다. WCAG 대비비가 어떻게 계산되는지와 HSL 명도로 짐작하면 왜 틀리는지 정리했습니다.
회색 글자가 흰 배경에서 읽히는지 판단할 때 화면을 보고 정하는 방법이 있습니다. 문제는 기준선이 눈으로 구분되지 않는 자리에 있다는 것입니다.
#767676 흰 배경 대비 4.54:1 통과
#777777 흰 배경 대비 4.48:1 실패
한 단계 차이입니다. 화면에서는 같은 회색으로 보입니다.
계산 방법
WCAG 2.x의 대비비는 두 색의 상대 휘도로 정의됩니다.
먼저 각 채널을 0~1로 정규화하고 감마를 되돌립니다.
c ≤ 0.03928 → c / 12.92
c > 0.03928 → ((c + 0.055) / 1.055) ^ 2.4
그다음 사람 눈의 채널별 민감도로 가중합을 냅니다.
L = 0.2126·R + 0.7152·G + 0.0722·B
대비비는 두 휘도에 0.05를 더해 나눈 값입니다.
대비비 = (밝은 쪽 L + 0.05) / (어두운 쪽 L + 0.05)
값의 범위는 1:1(같은 색)부터 21:1(검정과 흰색)까지입니다.
기준
| 대상 | 최소 대비비 |
|---|---|
| 본문 텍스트 (AA) | 4.5:1 |
| 큰 텍스트 — 18pt 이상 또는 굵은 14pt 이상 (AA) | 3:1 |
| UI 요소·그래픽 경계 (AA) | 3:1 |
| 본문 텍스트 (AAA) | 7:1 |
| 큰 텍스트 (AAA) | 4.5:1 |
실제 색으로 계산하면 이렇게 나옵니다.
| 전경 | 배경 | 대비비 | 본문 | 큰 텍스트 |
|---|---|---|---|---|
#767676 |
#ffffff |
4.54 | 통과 | 통과 |
#777777 |
#ffffff |
4.48 | 실패 | 통과 |
#999999 |
#ffffff |
2.85 | 실패 | 실패 |
#0066cc |
#ffffff |
5.57 | 통과 | 통과 |
#595959 |
#ffffff |
7.00 | 통과 | 통과 |
#ffffff |
#000000 |
21.00 | 통과 | 통과 |
#767676이 흰 배경에서 본문 기준을 만족하는 가장 밝은 회색입니다. 그보다 밝으면 실패합니다. 디자인 시스템에 보조 텍스트 색을 정할 때 이 값이 경계가 됩니다.
0.7152가 하는 일
가중치를 보면 초록이 71.5%, 빨강이 21.3%, 파랑이 7.2%입니다. 파랑은 거의 기여하지 않습니다. 그래서 순색끼리 비교하면 결과가 직관과 크게 어긋납니다.
빨강 #ff0000 상대 휘도 0.2126 흰 배경 대비 4.00:1
초록 #00ff00 상대 휘도 0.7152 흰 배경 대비 1.37:1
파랑 #0000ff 상대 휘도 0.0722 흰 배경 대비 8.59:1
셋 다 HSL 명도가 50%입니다. 그런데 흰 배경에서 파랑은 8.59:1로 넉넉히 통과하고 초록은 1.37:1로 거의 안 보입니다. HSL의 L 값으로 접근성을 판단하면 이렇게 틀립니다.
노란색도 같습니다.
#ffff00 흰 배경 1.07:1 거의 보이지 않음
#ffff00 검정 배경 19.56:1 아주 잘 보임
노란 경고 배지를 흰 배경에 흰 글씨 없이 노란 글씨로 쓰면 읽히지 않습니다.
자주 걸리는 자리
- 플레이스홀더 텍스트 — 흐리게 하려고
#aaa같은 값을 쓰면 대부분 실패합니다 - 비활성 버튼 — 비활성 상태는 대비 요구에서 제외되지만, 실제로는 사용자가 읽어야 하는 경우가 많습니다
- 그라데이션 위의 글자 — 가장 불리한 지점에서 계산해야 합니다
- 이미지 위의 글자 — 이미지가 바뀌면 대비도 바뀝니다. 반투명 레이어를 깔고 그 합성 색으로 계산합니다
- 포커스 링 — UI 요소이므로 3:1이 필요합니다. 배경과 인접 색 양쪽에 대해 봐야 합니다
- 다크 모드 — 라이트 모드에서 통과한 색이 반전된 배경에서 실패하는 일이 흔합니다
반투명 색은 합성 후에 계산한다
rgba(0, 0, 0, 0.5)는 그 자체로 휘도가 없습니다. 배경과 합성된 결과 색을 구해야 합니다.
결과 = 전경·알파 + 배경·(1 - 알파)
이 계산은 감마 보정 전 sRGB 값에서 이뤄지고, 대비비 계산은 그 결과 색으로 다시 시작합니다. 순서를 바꾸면 값이 달라집니다.
WCAG 3의 APCA
지금 계산식은 얇은 글꼴이나 어두운 배경에서 실제 가독성과 어긋난다는 지적을 받아 왔습니다. WCAG 3 초안의 APCA는 글자 크기와 굵기까지 반영하는 다른 모델을 씁니다. 다만 아직 초안이고 법적 기준으로 쓰이는 것은 WCAG 2.x입니다. 지금 맞춰야 하는 것은 4.5:1입니다.
확인 순서
- 본문·보조 텍스트·링크 색을 배경색과 짝지어 계산합니다. 색 팔레트 단계에서 한 번에 하는 편이 낫습니다
- 큰 텍스트 예외를 적용했다면 실제 렌더 크기를 확인합니다.
18pt는 CSS에서24px입니다 - 다크 모드 팔레트를 따로 계산합니다. 반전만으로는 통과가 보장되지 않습니다
- 반투명이 섞인 자리는 합성된 색으로 다시 계산합니다
- 브라우저 개발자 도구의 색상 선택기에도 대비비가 표시됩니다. 요소를 직접 검사할 때 빠릅니다
tools.onuel.dev의 색상 변환에 색을 넣으면 HEX·RGB·HSL 표기와 함께 흰 배경·검은 배경에 대한 대비비를 AA 통과 여부와 같이 보여 줍니다. 위에서 본 순색 세 개를 넣어 보면 HSL 명도가 셋 다 50%인데 대비비는 갈리는 것이 그대로 나옵니다. 흰색·검은색이 아닌 임의의 두 색을 비교하려면 각각의 값을 넣고 위 공식으로 직접 계산해야 합니다.
- #접근성
- #색상
- #WCAG