색상만으로 정보를 전달하고 있지 않은가?
이전 글에서 스크린 리더와 키보드 내비게이션을 다뤘습니다. 하지만 접근성은 시각 장애에만 국한되지 않습니다. 저시력, 색맹, 전정 장애 등 시각적 요소와 관련된 접근성 문제도 중요합니다.
이번 글에서는 세 가지 질문을 던집니다.
- 텍스트를 읽을 수 있는가?, 대비 비율
- 색을 구분하지 못해도 정보를 얻을 수 있는가?, 색맹 고려
- 움직이는 요소가 불편하지 않은가?, 모션 감소
색 대비 기준: WCAG AA와 AAA
WCAG (Web Content Accessibility Guidelines) 는 텍스트와 배경 사이의 대비 비율 (contrast ratio) 을 구체적인 숫자로 규정합니다.
| 수준 | 일반 텍스트 | 큰 텍스트 (24px+ 또는 18.66px 볼드) | UI 컴포넌트 |
|---|---|---|---|
| AA | 4.5 : 1 | 3 : 1 | 3 : 1 |
| AAA | 7 : 1 | 4.5 : 1 | - |
대비 비율의 범위는 1:1 (동일 색상) 에서 21:1 (흰색 위 검정) 까지입니다. 비율이 높을수록 읽기 쉽습니다.
대비 비율 = (밝은 색의 상대 휘도 + 0.05) / (어두운 색의 상대 휘도 + 0.05)
예) 흰색(#fff)과 회색(#767676)
L_white = 1.0, L_gray = 0.176
비율 = (1.0 + 0.05) / (0.176 + 0.05) = 4.54:1 → AA 통과아래 시각화에서 각 대비 수준이 실제로 어떻게 보이는지 확인하세요. 마지막 단계에서는 색상만으로 정보를 전달할 때의 문제도 함께 보여줍니다.
색맹 고려
전 세계 남성의 약 8%, **여성의 약 0.5%**가 색각 이상이 있습니다. 가장 흔한 유형은 적록 색맹으로, 빨간색과 초록색을 구분하기 어렵습니다.
| 유형 | 영향 | 비율 (남성) |
|---|---|---|
| 제1색맹 (Protanopia) | 빨간색 인식 불가 | ~1% |
| 제2색맹 (Deuteranopia) | 초록색 인식 불가 | ~1% |
| 제1색약 (Protanomaly) | 빨간색 인식 감소 | ~1% |
| 제2색약 (Deuteranomaly) | 초록색 인식 감소 | ~5% |
실무에서의 원칙:
- 색상에만 의존하지 말 것, 아이콘, 패턴, 텍스트를 함께 사용
- 성공/실패를 빨강/초록으로만 표시하지 말 것, ✓/✕ 아이콘 병행
- 그래프에서 색 구분이 어려우면 패턴 (빗금, 점선) 을 추가
- 링크를 색상만으로 구분하지 말 것, 밑줄을 함께 사용
/* ❌ 색상만으로 링크 구분 */
a { color: blue; text-decoration: none; }
/* ✅ 밑줄 + 색상으로 구분 */
a { color: blue; text-decoration: underline; }대비 검사 도구
대비 비율을 직접 계산할 필요는 없습니다. 도구를 사용하세요.
Chrome DevTools, Elements 패널에서 색상 값을 클릭하면 대비 비율이 표시됩니다. AA/AAA 통과 여부도 함께 보여줍니다.
WebAIM Contrast Checker, 전경색과 배경색을 입력하면 즉시 대비 비율을 계산합니다. 가장 많이 사용되는 온라인 도구입니다.
Lighthouse, Chrome DevTools의 Lighthouse 탭에서 접근성 감사를 실행하면 대비 문제를 자동으로 찾아줍니다.
// 프로그래밍 방식으로 대비 비율 계산
function relativeLuminance(hex) {
const [r, g, b] = [1, 3, 5].map((i) => {
const c = parseInt(hex.slice(i, i + 2), 16) / 255;
return c <= 0.04045
? c / 12.92
: Math.pow((c + 0.055) / 1.055, 2.4);
});
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
function contrastRatio(hex1, hex2) {
const l1 = relativeLuminance(hex1);
const l2 = relativeLuminance(hex2);
const lighter = Math.max(l1, l2);
const darker = Math.min(l1, l2);
return (lighter + 0.05) / (darker + 0.05);
}
contrastRatio("#ffffff", "#767676"); // 4.54 → AA 통과모션 감소: prefers-reduced-motion
일부 사용자는 화면의 움직임으로 인해 어지러움, 메스꺼움, 두통을 겪습니다. 전정 장애 (vestibular disorders) 를 가진 사용자가 대표적입니다.
OS에서 "모션 줄이기" 설정을 켜면 CSS 미디어 쿼리 prefers-reduced-motion으로 감지할 수 있습니다.
/* 기본: 애니메이션 적용 */
.card {
transition: transform 0.3s ease;
}
.card:hover {
transform: scale(1.05);
}
/* 모션 줄이기 설정 시: 애니메이션 제거 또는 대체 */
@media (prefers-reduced-motion: reduce) {
.card {
transition: none;
}
.card:hover {
transform: none;
/* 대신 opacity 변경 같은 부드러운 대안 사용 */
opacity: 0.9;
}
}JavaScript에서도 확인할 수 있습니다.
// JS에서 모션 감소 설정 감지
const motionQuery = window.matchMedia(
"(prefers-reduced-motion: reduce)"
);
if (motionQuery.matches) {
// 애니메이션을 비활성화하거나 간소화
document.documentElement.classList.add("reduce-motion");
}
// 설정 변경 감지
motionQuery.addEventListener("change", (e) => {
if (e.matches) {
// 모션 감소 활성화됨
cancelAllAnimations();
}
});핵심 원칙:
- 모든 애니메이션을 없애는 것이 아니라, 과도한 모션을 줄이는 것
- 페이드인/페이드아웃은 유지해도 됨, 회전, 확대/축소, 슬라이드는 줄이거나 제거
- 5초 이상 지속되는 애니메이션은 정지 버튼 제공
- 자동 재생 캐러셀은
prefers-reduced-motion: reduce에서 정지
다크 모드와 접근성
다크 모드를 지원한다고 접근성이 자동으로 좋아지는 것은 아닙니다. 다크 모드에서도 대비 비율을 유지해야 합니다.
:root {
--text: #1a1a1a; /* 라이트: 거의 검정 */
--bg: #ffffff; /* 라이트: 흰색 */
/* 대비 비율: 약 17.4:1 ✅ */
}
@media (prefers-color-scheme: dark) {
:root {
--text: #e5e5e5; /* 다크: 밝은 회색 */
--bg: #171717; /* 다크: 거의 검정 */
/* 대비 비율: 약 15.4:1 ✅ */
}
}
/* ❌ 다크 모드에서 흔한 실수 */
@media (prefers-color-scheme: dark) {
:root {
--text: #888888; /* 너무 어두운 텍스트 */
--bg: #333333; /* 너무 밝은 배경 */
/* 대비 비율: 약 2.4:1 ❌ */
}
}텍스트 크기와 확대
WCAG 1.4.4는 텍스트를 200%까지 확대해도 콘텐츠가 유실되거나 기능이 깨지지 않아야 한다고 규정합니다.
px대신rem을 사용하면 사용자가 브라우저 기본 글꼴 크기를 변경할 때 함께 조정됨- 본문 텍스트는 최소 16px (1rem) 을 권장
max-width를ch단위로 설정하면 줄당 문자 수를 제한해 가독성 향상
/* ❌ 고정 px, 사용자 설정 무시 */
body { font-size: 14px; }
/* ✅ rem, 사용자 브라우저 설정에 반응 */
body { font-size: 1rem; } /* 기본 16px */
h1 { font-size: 2rem; } /* 32px */
/* 줄 길이 제한으로 가독성 향상 */
article { max-width: 70ch; }시각 접근성 체크리스트
| 항목 | 기준 |
|---|---|
| 텍스트 대비 | 일반 4.5:1 이상, 큰 텍스트 (24px+) 3:1 이상 (AA) |
| UI 컴포넌트 대비 | 3:1 이상 |
| 색상만으로 정보 전달 | ❌ 아이콘/텍스트/패턴 병행 |
| 링크 구분 | 색상 + 밑줄 |
| prefers-reduced-motion | 과도한 모션 제거 또는 대체 |
| 다크 모드 대비 | 라이트 모드와 동일한 기준 유지 |
| 텍스트 크기 | rem 사용, 200% 확대 대응 |
| 줄 길이 | 70~80ch 이내 권장 |
다음 글: 폼과 에러 처리
시각적 접근성을 확보했다면, 이제 사용자가 실제로 상호작용하는 폼을 살펴볼 차례입니다. 다음 글에서는 label 연결, 에러 메시지 전달, aria-live를 다룹니다.