연한 회색 글씨는 왜 읽기 어려울까: WCAG 명도 대비 계산법

흰 배경의 연한 회색 글씨가 접근성 검사에서 떨어지는 이유를 WCAG 2의 상대 휘도와 명도 대비 공식으로 설명하고, 4.5:1·3:1·7:1 기준과 다크 모드에서 주의할 점을 실제 색상 값으로 정리했습니다.

개발접근성

시안에서는 멋져 보였던 입력창의 안내 문구가 있습니다. 흰 배경에 #aaaaaa 정도의 연한 회색이라 화면이 깔끔해 보입니다. 그런데 한낮의 지하철 안에서 휴대폰으로 열어 보면 글자가 거의 보이지 않습니다. 화면 밝기를 낮춘 노트북이나, 노안이 시작된 부모님의 눈에서도 마찬가지입니다.

접근성 검사 도구는 이 글씨를 2.32:1이라는 숫자로 떨어뜨립니다. 이 숫자가 어디서 나오는지 알면, 감으로 회색을 고르지 않아도 됩니다.

흰 배경 위 회색 글씨 여섯 가지의 명도 대비. #cccccc는 1.61:1, #999999는 2.85:1로 불합격, #777777은 4.48:1로 큰 글씨에만 쓸 수 있고, #767676은 4.54:1로 본문 AA 기준 통과, #595959는 7.00:1로 AAA 통과, #1d1d1f는 16.83:1입니다. 아래에는 1:1부터 21:1까지의 로그 눈금 위에 3:1(큰 글씨·UI 요소), 4.5:1(본문 AA), 7:1(본문 AAA) 기준선이 표시되어 있습니다.

사람의 눈은 초록에 가장 민감하다

WCAG 2가 쓰는 것은 색의 상대 휘도(relative luminance), 즉 그 색이 얼마나 밝게 느껴지는지를 0(검정)부터 1(흰색)까지로 나타낸 값입니다. 계산은 두 단계입니다.

먼저 sRGB의 각 채널(0~255)을 255로 나눈 뒤, 화면이 밝기를 표현하는 비선형 곡선을 되돌려 선형 값으로 바꿉니다.

c = 값 / 255
c ≤ 0.04045 이면  c / 12.92
그 외에는         ((c + 0.055) / 1.055) ^ 2.4

그다음 세 채널에 가중치를 곱해 더합니다.

L = 0.2126 × R + 0.7152 × G + 0.0722 × B

초록의 가중치가 파랑의 열 배쯤 됩니다. 사람의 눈이 초록 빛에 훨씬 민감하기 때문입니다. 순수한 파랑 #0000ff가 채도는 강해도 흰 글씨를 올리면 잘 읽히는 이유, 노란색 #ffff00 위의 흰 글씨가 거의 안 보이는 이유가 여기에 있습니다.

(오래된 WCAG 문서에는 기준값이 0.03928로 적혀 있습니다. 8비트 색상에서는 두 값 사이에 들어가는 정수가 없어서 어느 쪽으로 계산해도 결과가 같습니다.)

대비는 밝은 쪽을 어두운 쪽으로 나눈 값

두 색의 휘도를 구했다면 명도 대비는 이렇게 나옵니다.

대비 = (밝은 쪽 L + 0.05) / (어두운 쪽 L + 0.05)

0.05는 화면에 비치는 주변 빛을 흉내 낸 값입니다. 이 덕분에 검정끼리 비교해도 0으로 나누는 일이 없고, 결과는 1:1(같은 색)부터 21:1(흰색과 검정)까지의 범위에 들어갑니다.

이 사이트의 초록색 강조색으로 직접 계산해 보겠습니다. #0a7f47은 R=10, G=127, B=71입니다. 선형 값으로 바꾸면 각각 약 0.003, 0.212, 0.063이고, 가중치를 적용하면 L ≈ 0.157입니다. 흰색의 L은 1이므로 대비는 (1 + 0.05) / (0.157 + 0.05) ≈ 5.07:1입니다. 본문 글씨 기준 4.5:1을 넘습니다.

조금 더 밝은 초록 #0e9e58은 3.47:1이 나옵니다. 눈으로 보기엔 충분히 진해 보여도, 흰 배경의 링크 색으로는 기준에 못 미칩니다. 그래서 이 사이트는 밝은 모드와 어두운 모드에서 강조색을 따로 씁니다.

기준은 글자 크기와 역할에 따라 다르다

대상 AA AAA WCAG 항목
일반 본문 글씨 4.5:1 7:1 1.4.3, 1.4.6
큰 글씨 (24px 이상, 굵게는 약 18.66px 이상) 3:1 4.5:1 1.4.3, 1.4.6
입력창 테두리, 아이콘, 포커스 표시 같은 UI 요소 3:1 — 1.4.11

큰 글씨 기준이 낮은 것은 획이 굵고 커지면 대비가 낮아도 알아보기 쉬워지기 때문입니다. 명세의 원래 단위는 18pt, 굵은 글씨는 14pt이고, 이를 CSS 픽셀로 옮긴 것이 24px과 약 18.66px입니다.

흥미로운 경계가 하나 있습니다. 흰 배경에서 4.5:1을 넘는 가장 밝은 회색은 #767676(4.54:1)입니다. 한 단계 밝은 #777777은 4.48:1로 떨어집니다. 디자인 시스템에서 “보조 글씨 회색”을 정할 때 이 값을 기억해 두면 편합니다.

기준에서 빠지는 것도 있습니다. 비활성화된 버튼의 글씨, 순수한 장식, 로고 속 글자는 대비 기준을 적용하지 않습니다. 반면 입력창의 안내 문구(placeholder)는 사용자가 읽어야 하는 글씨이므로 기준 안에 들어갑니다. 처음 예로 든 연한 회색 안내 문구가 문제가 되는 이유입니다.

대비만 맞추면 끝이 아니다

빨강과 초록은 색상은 정반대여도 휘도가 비슷할 수 있습니다. #ff0000과 #00ff00의 대비는 2.91:1에 불과합니다. 적록 색약이 있는 사람에게는 두 색이 거의 같은 밝기의 칙칙한 색으로 보입니다.

WCAG 1.4.1은 그래서 색만으로 정보를 전달하지 말라고 합니다. 입력 오류를 빨간 테두리로만 표시하지 말고 아이콘이나 “필수 항목입니다” 같은 글을 함께 두고, 그래프는 색과 함께 선 모양이나 이름표로도 구분하는 식입니다. 내가 고른 색이 어떻게 보일지는 색각이상 시뮬레이터로 확인할 수 있습니다.

다크 모드에서 다시 계산해야 하는 이유

밝은 모드에서 통과한 색을 그대로 어두운 배경에 올리면 결과가 달라집니다. 앞의 #0a7f47은 검정 배경에서 4.14:1로 떨어집니다. 이 사이트가 어두운 모드에서 #1ed47c(검정 대비 10.76:1)로 강조색을 바꾸는 이유입니다.

어두운 모드에서는 반대 방향의 실수도 흔합니다. 순백 #ffffff와 순흑 #000000은 21:1로 대비는 최대지만, 넓은 면적의 글에서는 눈이 부시다는 사람이 많습니다. 그래서 많은 디자인 시스템이 본문 글씨를 약간 회색빛 흰색으로, 배경을 짙은 회색으로 둡니다. 이렇게 낮춰도 15:1 안팎이라 기준에는 여유가 있습니다.

다음 기준은 아직 초안이다

WCAG 2의 공식은 단순한 대신, 어두운 색끼리의 대비를 실제보다 좋게 평가하는 경향이 있다는 비판을 받아 왔습니다. 차기 버전인 WCAG 3의 초안에는 APCA라는 새 계산법이 후보로 거론되지만, 아직 작업 초안(Working Draft) 단계입니다. 법이나 조달 기준, 접근성 인증은 지금도 WCAG 2.x를 기준으로 합니다. 새 방식을 참고하더라도 WCAG 2 기준은 함께 통과시키는 편이 안전합니다.

색을 고를 때 바로 계산하기

색상 코드 변환 도구에 HEX, RGB, HSL 중 어떤 형식으로든 색을 넣으면, 흰 글씨·검은 글씨와의 명도 대비와 AA·AAA 통과 여부를 함께 보여 줍니다. #777777과 #767676을 차례로 넣어 보면 한 단계 차이로 결과가 갈리는 것을 볼 수 있습니다.

참고

  • W3C, Web Content Accessibility Guidelines (WCAG) 2.2: 1.4.1 Use of Color, 1.4.3 Contrast (Minimum), 1.4.6 Contrast (Enhanced), 1.4.11 Non-text Contrast, 용어 정의 “contrast ratio”, “relative luminance”
  • W3C, Understanding Success Criterion 1.4.3: Contrast (Minimum)
  • W3C, WCAG 3.0 Working Draft

블로그로