도입 스토리
6개월이 지났습니다.
김개발은 이제 팀의 접근성 챔피언이었습니다. 신규 입사자에게 NVDA를 처음 사용하는 법을 알려주는 사람이 되었습니다.
"멘토님, 제가 처음 NVDA를 켰을 때 너무 무서웠는데." 김개발이 웃으며 말했습니다.
"이제 무서워요?"
"아니요. 이제는 코드를 짜면서 자연스럽게 '스크린리더가 이걸 어떻게 읽을까' 생각해요."
"그게 접근성이 문화가 된 거예요." 박멘토가 말했습니다. "기술이 아니라 습관."
핵심 개념 설명
WCAG 4대 원칙 총정리
원칙 1 — 인식의 용이성 (Perceivable)
모든 정보는 사용자가 인식할 수 있는 방식으로 제공되어야 합니다.
| 번호 | 기준 | 핵심 구현 |
|---|---|---|
| 1.1.1 | 텍스트 대안 | alt 속성, aria-label |
| 1.2.x | 시간 기반 미디어 | <track kind="captions"> |
| 1.3.1 | 정보와 관계 | 시맨틱 HTML, <table scope> |
| 1.3.3 | 감각적 특성 | 색+아이콘+텍스트 병행 |
| 1.4.1 | 색의 사용 | 색만으로 정보 전달 금지 |
| 1.4.3 | 명도 대비 | 4.5:1 (일반), 3:1 (큰 텍스트) |
| 1.4.4 | 텍스트 크기 조정 | rem 단위, 200% 확대 대응 |
| 1.4.11 | 비텍스트 대비 | UI 컴포넌트 3:1 |
| 1.4.12 | 텍스트 간격 | line-height 1.5+ |
원칙 2 — 운용의 용이성 (Operable)
모든 기능은 키보드로 사용할 수 있어야 합니다.
| 번호 | 기준 | 핵심 구현 |
|---|---|---|
| 2.1.1 | 키보드 접근 | 모든 기능 키보드 사용 가능 |
| 2.1.2 | 포커스 함정 없음 | 모달 포커스 트랩 + Escape |
| 2.2.1 | 시간 제한 | 세션 연장/중지 옵션 |
| 2.2.2 | 일시 정지, 중지 | 자동 재생 5초+ → 정지 기능 |
| 2.3.1 | 깜빡임 | 초당 3회 이상 금지 |
| 2.4.1 | 건너뛰기 | 스킵 내비게이션 |
| 2.4.2 | 페이지 제목 | 고유한 <title> |
| 2.4.3 | 포커스 순서 | DOM 순서 = 논리 순서 |
| 2.4.4 | 링크 목적 | 구체적인 링크 텍스트 |
| 2.4.7 | 포커스 가시성 | :focus-visible 스타일 |
| 2.5.8 | 타겟 크기 | 24×24dp 이상 |
원칙 3 — 이해의 용이성 (Understandable)
콘텐츠와 UI 동작을 이해할 수 있어야 합니다.
| 번호 | 기준 | 핵심 구현 |
|---|---|---|
| 3.1.1 | 페이지 언어 | <html lang="ko"> |
| 3.1.2 | 부분 언어 | <span lang="en"> |
| 3.2.1 | 포커스 시 동작 | 자동 동작 금지 |
| 3.2.2 | 입력 시 동작 | 자동 페이지 이동 금지 |
| 3.3.1 | 오류 식별 | aria-invalid + 오류 메시지 |
| 3.3.2 | 레이블 제공 | <label> + aria-describedby |
| 3.3.3 | 오류 제안 | 구체적인 수정 방법 안내 |
| 3.3.4 | 오류 방지 | 중요 작업 확인 단계 |
원칙 4 — 견고성 (Robust)
현재와 미래의 보조기기에서 올바르게 해석되어야 합니다.
| 번호 | 기준 | 핵심 구현 |
|---|---|---|
| 4.1.1 | 파싱 | 유효한 HTML, 고유 id |
| 4.1.2 | 이름, 역할, 값 | ARIA 3요소 올바른 사용 |
| 4.1.3 | 상태 메시지 | aria-live, role="status/alert" |
즉시 시작할 수 있는 10가지 개선
지금 당장 코드에서 확인하고 수정할 수 있는 것들입니다.
1. <img> 태그에 alt 속성이 있는가?
2. <html lang="ko">가 설정되어 있는가?
3. 모든 폼 필드에 <label>이 연결되어 있는가?
4. * { outline: none; }이 없는가?
5. <title>이 페이지마다 고유한가?
6. <main>, <nav>, <header>, <footer>가 사용되고 있는가?
7. 페이지 첫 번째 요소가 스킵 링크인가?
8. 색만으로 정보를 전달하는 요소가 없는가?
9. Tab 키만으로 모든 기능을 사용할 수 있는가?
10. 200% 확대 시 레이아웃이 깨지지 않는가?
도구 참조
| 도구 | 용도 | URL/설치 |
|---|---|---|
| axe DevTools | 자동화 검사 | Chrome 확장 프로그램 |
| Lighthouse | 점수 측정 | Chrome DevTools 내장 |
| WAVE | 시각적 감사 | wave.webaim.org |
| Colour Contrast Analyser | 색상 대비 측정 | 데스크톱 앱 |
| NVDA | Windows 스크린리더 | nvaccess.org |
| axe-core | Jest/Playwright 통합 | npm install axe-core |
| eslint-plugin-jsx-a11y | React 린팅 | npm install eslint-plugin-jsx-a11y |
단계별 실습
따라하기: 10가지 체크리스트 자기 점검
현재 작업 중인 프로젝트에서 위 10가지를 직접 확인합니다.
// 브라우저 콘솔에서 빠르게 확인하는 스크립트const checks = { '페이지 언어': document.documentElement.lang, '스킵 링크': document.querySelector('a[href="#main-content"]')?.textContent, 'alt 없는 이미지': document.querySelectorAll('img:not([alt])').length, '레이블 없는 입력': [...document.querySelectorAll('input')].filter(i => !document.querySelector(`label[for="${i.id}"]`) && !i.getAttribute('aria-label') ).length, 'outline none': getComputedStyle(document.querySelector(':focus-visible') || document.body).outline,};console.table(checks);
응용하기: 팀 접근성 문화 지수 측정
팀의 현재 접근성 성숙도를 평가하는 간단한 체크리스트입니다.
## 팀 접근성 성숙도 체크리스트
### Level 1 — 기초 (0~3점)
□ 이미지에 alt 텍스트 정책이 있는가
□ 포커스 스타일이 제거되지 않는가
□ 색만으로 정보를 전달하지 않는가
### Level 2 — 체계화 (4~6점)
□ PR에 접근성 체크리스트가 있는가
□ axe DevTools를 개발 중 사용하는가
□ 스크린리더 테스트를 릴리스마다 하는가
### Level 3 — 자동화 (7~9점)
□ CI/CD에 접근성 게이팅이 있는가
□ 컴포넌트 라이브러리에 접근성 가이드가 있는가
□ 접근성 챔피언이 지정되어 있는가
### Level 4 — 문화 (10점)
□ 접근성이 기획 단계부터 요구사항에 포함되는가
□ 팀원 모두가 키보드 탐색으로 개발 결과를 확인하는가
□ 사용자 테스트에 장애 당사자가 참여하는가
정리와 확인
핵심 내용 요약
- POUR 원칙: Perceivable → Operable → Understandable → Robust
- 즉시 시작 10가지: alt, lang, label, outline, title, 랜드마크, skip, 색, keyboard, 확대
- 성숙도 레벨: 기초 → 체계화 → 자동화 → 문화
- 접근성은 과정: 완성이 없는 지속적인 개선
다음 챕터에서는 웹접근성의 미래와 계속 학습할 수 있는 리소스를 안내합니다.