감에 의존하지 않고 WCAG 색 대비 충족하기

대비율이 무엇을 측정하는지, 텍스트와 인터페이스 구성 요소에 대한 AA와 AAA 기준값은 얼마인지, 그리고 흰 바탕의 회색 글자에서 매번 조용히 기준을 놓치는 실수는 무엇인지 설명합니다.

일반 본문 텍스트의 경우 WCAG 레벨 AA는 배경 대비 최소 4.5:1의 대비율을 요구합니다. 큰 텍스트에는 3:1이 필요합니다. 인터페이스 구성 요소와 의미를 담은 그래픽에도 3:1이 필요합니다. 레벨 AAA는 텍스트를 7:1로, 큰 텍스트를 4.5:1로 올립니다. 대비율은 1:1(동일한 색)부터 21:1(순수한 검정 위의 순수한 흰색)까지의 범위를 갖습니다.

이것은 눈으로 판단할 수 없습니다. 모니터에서 비슷하게 읽히는 두 조합이 기준선의 양쪽에 각각 놓여 있을 수 있으므로 대비율은 반드시 계산해야 합니다.

기준값

대상AAAAA
일반 텍스트4.5:17:1
큰 텍스트3:14.5:1
인터페이스 구성 요소와 그래픽 객체3:1더 높은 기준 없음

이 값들은 세 가지 성공 기준에서 나옵니다. AA의 1.4.3 대비(최소), AAA의 1.4.6 대비(향상), 그리고 AA의 1.4.11 텍스트가 아닌 콘텐츠의 대비입니다. 마지막 기준은 컨트롤의 시각적 경계와 그래픽에서 이해에 필요한 부분을 다룹니다.

큰 텍스트는 18포인트 이상, 굵은 글씨라면 14포인트 이상을 뜻하며, 대략 24px 보통 굵기 또는 18.5px 정도의 굵은 글씨에 해당합니다. 이것은 "제목"을 뜻하지 않습니다. 20px 제목은 이 규칙에서 일반 텍스트이며 4.5:1을 온전히 충족해야 합니다.

몇 가지는 예외입니다. 순전히 장식용인 텍스트, 비활성 컨트롤 안의 텍스트, 다른 중요한 시각 요소를 담은 그림의 일부인 텍스트, 그리고 로고타입이 그렇습니다. 자리 표시 텍스트와 도움말 텍스트는 예외가 아닙니다.

대비율이 실제로 측정하는 것

이 공식은 두 색의 상대 휘도를 비교합니다.

ratio = (L_lighter + 0.05) / (L_darker + 0.05)

상대 휘도는 색이 얼마나 많은 빛을 내는지를 0(검정)에서 1(흰색) 사이의 수로 나타낸 값입니다. 각 채널에서 sRGB 감마 곡선을 되돌린 다음 가중치를 적용해 계산합니다.

L = 0.2126 R + 0.7152 G + 0.0722 B     (on linearised channels)

양쪽에 더해진 0.05는 화면에 반사되는 약간의 주변광을 모델링한 값이며, 최댓값이 무한대가 아니라 21인 이유가 이것입니다.

여기에서 두 가지가 따라옵니다. 대비율은 색상이 아니라 휘도에만 의존하므로, 색상이 크게 다른 두 색이 서로 겹쳤을 때 거의 보이지 않을 수 있습니다. 그리고 대비율은 대칭이므로 어느 쪽을 전경으로 부르든 상관없습니다.

상대 휘도는 밝기가 아닙니다

가중치를 보십시오. 초록이 휘도의 약 72%, 빨강이 약 21%를 담당하고, 파랑은 겨우 7%입니다. 이는 색이 얼마나 선명해 보이는지가 아니라 인간의 시각을 모델링한 것이며, 익숙해지기 전까지는 잘못된 것처럼 느껴지는 결과를 내놓습니다.

  • 흰 바탕의 순수한 노랑 #FFFF00은 약 1.07:1로 거의 보이지 않습니다. 노랑이 강한 색처럼 느껴지는데도 그렇습니다.
  • 같은 노랑이 검정 위에서는 약 19.6:1로, 검정 위의 흰색에 거의 맞먹습니다.
  • 순수한 파랑 #0000FF은 검정 위에서 약 2.4:1이라 모든 기준에서 탈락합니다. 굵고 선명해 보이는데도 그렇습니다.

HSL의 명도가 좋은 대용값이 되지 못하는 이유도 이것입니다. HSL에서 둘 다 명도 50%인 두 색의 휘도가 크게 다를 수 있습니다. HSL은 색상과 명도를 서로 독립적인 것으로 다루지만 시각은 그렇지 않기 때문입니다. 명도 한 칸이 곧 대비 한 칸이라고 가정하지 말고, 변환한 다음 측정하십시오.

계속 반복되는 실수들

흰 바탕의 회색 본문 텍스트. 가장 흔한 문제입니다. 흰 바탕에서 AA를 통과하는 가장 밝은 회색은 약 #767676이며 4.54:1이 나옵니다. 한 단계만 더 밝은 #777777은 4.48:1로 탈락합니다. #999999 같은 인기 있는 "차분한" 회색은 2.9:1 언저리로, 요구치의 3분의 2에도 못 미칩니다. 흰 바탕에서 AAA를 원한다면 대략 #595959가 필요하며, 이 값이 정확히 7:1입니다.

자리 표시 텍스트와 도움말 텍스트. 부차적인 정보라는 이유로 본문보다 몇 단계 밝게 설정되곤 합니다. 그래도 텍스트이므로 여전히 4.5:1이 필요합니다.

반투명한 색. 요소가 불투명도 60%로 놓여 있다면 선언된 색으로 계산한 대비율은 의미가 없습니다. 화면에 실제로 나타나는 합성 결과 색을 구한 다음 그 값을 측정하십시오.

이미지, 그라데이션, 동영상 위의 텍스트. 대비율이 픽셀마다 달라지며, 중요한 것은 가장 나쁜 픽셀입니다. 사진이 계속 어두울 것이라고 기대하는 대신 텍스트 뒤에 스크림을 두는 것이 보통의 해법입니다.

브랜드 색 버튼. 중간 톤 브랜드 색 위의 흰 글자는 3:1과 4.5:1 사이에 놓이는 일이 매우 잦아서, 그래픽 객체로는 통과하고 레이블로는 탈락합니다. 버튼을 더 어둡게 하거나, 탈락한다는 사실을 알고 받아들이십시오.

포커스 표시와 아이콘만 있는 버튼. 둘 다 3:1의 텍스트 아닌 콘텐츠 규칙에 해당합니다. 같은 색의 살짝 다른 톤으로 만든 포커스 링이 흔히 놓치는 사례이고, 버튼의 유일한 내용이 회색 아이콘인 경우도 마찬가지입니다.

반전으로 만든 다크 모드. 밝은 팔레트를 뒤집어도 대비율은 유지되지 않습니다. 휘도가 중간값을 기준으로 대칭이 아니기 때문입니다. 순수한 검정 위의 순수한 흰색은 최댓값인 21:1을 내지만 그 번짐을 불편해하는 사람이 많습니다. 그래서 아주 어두운 회색 위에 약간 누그러뜨린 흰색을 쓰는 방식, 예를 들어 #121212 위의 #E6E6E6으로 약 15:1을 내는 방식이 흔한 절충안입니다.

스크린샷에서 측정하기. 안티에일리어싱된 텍스트의 가장자리를 스포이드로 찍으면 텍스트 색이 아니라 텍스트와 배경이 섞인 값을 얻습니다. 굵은 획의 한가운데를 찍거나, 더 좋게는 CSS에서 값을 직접 읽으십시오.

감에 의존하지 않는 작업 방식

배경을 먼저 확정한 다음, 전경을 어둡게 하거나 밝게 해서 기준값을 약간의 여유와 함께 넘기고, 그 조합을 기록하십시오. 승인된 색이 아니라 승인된 조합으로 팔레트를 구성하십시오. 색 하나만으로는 접근성을 갖출 수 없고 오직 조합에서만 갖출 수 있습니다. 기본 상태만이 아니라 모든 상태를 확인하고, 다크 모드를 제공한다면 두 테마 모두를 확인하십시오.

마지막으로 한 가지 덧붙입니다. 더 새로운 지각 모델인 APCA가 향후 WCAG 버전을 위해 개발되고 있으며, 특히 어두운 배경 위의 밝은 텍스트에서 꽤 다르게 동작합니다. 알아둘 가치는 있지만, 오늘 준수해야 할 수치는 위에 정리한 WCAG 2의 대비율입니다.