개발 이야기3분 읽기

색 대비비는 눈으로 판단할 수 없다

회색 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입니다.

확인 순서

  1. 본문·보조 텍스트·링크 색을 배경색과 짝지어 계산합니다. 색 팔레트 단계에서 한 번에 하는 편이 낫습니다
  2. 큰 텍스트 예외를 적용했다면 실제 렌더 크기를 확인합니다. 18pt는 CSS에서 24px입니다
  3. 다크 모드 팔레트를 따로 계산합니다. 반전만으로는 통과가 보장되지 않습니다
  4. 반투명이 섞인 자리는 합성된 색으로 다시 계산합니다
  5. 브라우저 개발자 도구의 색상 선택기에도 대비비가 표시됩니다. 요소를 직접 검사할 때 빠릅니다

tools.onuel.dev색상 변환에 색을 넣으면 HEX·RGB·HSL 표기와 함께 흰 배경·검은 배경에 대한 대비비를 AA 통과 여부와 같이 보여 줍니다. 위에서 본 순색 세 개를 넣어 보면 HSL 명도가 셋 다 50%인데 대비비는 갈리는 것이 그대로 나옵니다. 흰색·검은색이 아닌 임의의 두 색을 비교하려면 각각의 값을 넣고 위 공식으로 직접 계산해야 합니다.

  • #접근성
  • #색상
  • #WCAG