웹 접근성(a11y) 실전 가이드: WCAG 2.2 기준
웹 접근성의 핵심 원칙, WCAG 2.2 주요 기준, 개발자가 바로 적용할 수 있는 체크리스트를 정리했다.
웹 접근성이라고 하면 "장애인을 위한 것"이라고만 생각하기 쉬운데, 범위가 훨씬 넓다. 한 손으로 폰을 쓰는 사람, 밝은 햇빛 아래에서 화면을 보는 사람, 마우스 없이 키보드만 쓰는 사람, 일시적으로 팔을 다쳐서 한 손만 쓸 수 있는 사람. 접근성이 좋은 웹사이트는 이 모든 상황에서 더 잘 작동한다.
왜 신경 써야 하나
세 가지 이유가 있다.
법적 의무. 한국은 「장애인차별금지법」에 따라 공공기관과 일정 규모 이상의 민간 사업자에게 웹 접근성 준수를 의무화하고 있다. 미국은 ADA(Americans with Disabilities Act) 위반으로 소송이 나오는 경우가 매년 수천 건이다. 도미노 피자가 시각 장애인이 웹사이트를 이용할 수 없다는 이유로 패소한 판례가 유명하다.
비즈니스 관점. 전 세계 인구의 약 15%가 어떤 형태로든 장애를 가지고 있다. 접근성을 무시하면 이 사용자들을 잃는 거다. 또한 접근성이 좋은 사이트는 일반 사용자의 경험도 개선된다.
SEO. 시맨틱한 HTML, 적절한 heading 구조, alt 텍스트, 명확한 링크 텍스트 — 접근성을 지키면 자연스럽게 SEO도 좋아진다. 검색 엔진 크롤러도 결국 "보지 못하는 사용자"와 비슷하게 페이지를 해석하니까.
WCAG 2.2 핵심 — POUR 원칙
WCAG(Web Content Accessibility Guidelines)는 W3C에서 만든 웹 접근성 국제 표준이다. 2.2 버전이 2023년에 발표됐고, 네 가지 원칙(POUR)으로 구성돼 있다.
Perceivable (인지 가능)
콘텐츠를 사용자가 인식할 수 있어야 한다. 시각으로만 전달되는 정보는 안 된다.
- 이미지에 대체 텍스트(
alt) 제공 - 동영상에 자막 제공
- 색상만으로 정보를 전달하지 않기 (색맹 사용자 고려)
- 충분한 색상 대비 유지
Operable (조작 가능)
인터페이스를 조작할 수 있어야 한다. 마우스 없이도.
- 모든 기능을 키보드로 사용 가능해야 함
- 시간 제한이 있는 콘텐츠는 조절 가능해야 함
- 깜빡이는 콘텐츠는 초당 3회 이하
- 명확한 내비게이션 제공
Understandable (이해 가능)
콘텐츠와 인터페이스의 동작을 이해할 수 있어야 한다.
- 페이지 언어 명시 (
lang속성) - 예측 가능한 인터페이스 동작
- 입력 오류 시 명확한 안내 제공
- 일관된 내비게이션
Robust (견고함)
다양한 기술(브라우저, 보조 기술)에서 콘텐츠가 올바르게 해석될 수 있어야 한다.
- 올바른 HTML 마크업
- 이름, 역할, 값이 프로그래밍적으로 결정 가능
- 상태 메시지가 보조 기술에 전달됨
시맨틱 HTML — 기본 중의 기본
접근성의 출발점은 시맨틱 HTML이다. div로 모든 걸 만들고 CSS로 모양만 맞추는 건 시각적으로는 똑같아 보여도, 스크린 리더에게는 의미 없는 텍스트 더미일 뿐이다.
<!-- 나쁜 예 -->
<div class="header">
<div class="nav">
<div class="nav-item" onclick="goHome()">홈</div>
<div class="nav-item" onclick="goAbout()">소개</div>
</div>
</div>
<div class="main">
<div class="title">접근성 가이드</div>
<div class="text">내용...</div>
</div>
<!-- 좋은 예 -->
<header>
<nav>
<a href="/">홈</a>
<a href="/about">소개</a>
</nav>
</header>
<main>
<h1>접근성 가이드</h1>
<p>내용...</p>
</main>
차이가 뭘까? 스크린 리더는 <nav>를 만나면 "내비게이션"이라고 알려주고, <main>에서는 "메인 콘텐츠"로 바로 이동할 수 있게 해준다. <h1>은 페이지의 주제가 뭔지 알려준다. div에 클래스만 붙여놓으면 이 정보가 전부 사라진다.
자주 무시되는 시맨틱 태그들:
<header>,<footer>,<main>,<aside>— 페이지 구조<nav>— 내비게이션 영역<article>— 독립적인 콘텐츠 단위<section>— 주제별 그룹핑<button>— 클릭 가능한 동작.div에onClick달지 말고 이걸 쓰자<time>— 날짜/시간 정보<figure>+<figcaption>— 이미지와 캡션
ARIA — 시맨틱만으로 부족할 때
ARIA(Accessible Rich Internet Applications)는 HTML만으로 표현할 수 없는 의미를 추가하는 속성이다. 동적인 웹 애플리케이션에서 주로 필요하다.
하지만 ARIA의 첫 번째 규칙이 있다: 네이티브 HTML 요소로 해결할 수 있으면 ARIA를 쓰지 마라.
<button>으로 될 걸 <div role="button">으로 만들면 키보드 이벤트, 포커스 처리 등을 전부 직접 구현해야 한다. 네이티브 요소가 공짜로 제공하는 기능을 왜 굳이 다시 만드나.
ARIA가 꼭 필요한 경우들:
<!-- 탭 인터페이스 -->
<div role="tablist">
<button role="tab" aria-selected="true" aria-controls="panel1">탭 1</button>
<button role="tab" aria-selected="false" aria-controls="panel2">탭 2</button>
</div>
<div role="tabpanel" id="panel1">탭 1 내용</div>
<!-- 라이브 영역 — 동적으로 변하는 콘텐츠 알림 -->
<div aria-live="polite">검색 결과 42건을 찾았습니다.</div>
<!-- 모달 다이얼로그 -->
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
<h2 id="dialog-title">설정</h2>
<!-- 내용 -->
</div>
<!-- 시각적으로만 표시되는 정보에 라벨 추가 -->
<button aria-label="메뉴 닫기">✕</button>
aria-live="polite"는 스크린 리더에게 "이 영역이 바뀌면 사용자에게 알려줘"라고 말하는 거다. 검색 결과 갱신, 폼 제출 성공/실패 메시지 같은 데 쓴다.
키보드 내비게이션
마우스를 쓸 수 없는 사용자는 키보드로 웹을 탐색한다. Tab으로 요소 사이를 이동하고, Enter나 Space로 활성화하고, Escape로 닫고, 화살표키로 목록을 탐색한다.
개발하면서 체크할 것들:
포커스가 보여야 한다. 기본 outline을 outline: none으로 지워버리는 CSS가 흔한데, 이러면 현재 어떤 요소에 포커스가 있는지 알 수 없다. 기본 outline이 디자인에 안 맞으면, :focus-visible로 대체 스타일을 제공해야 한다.
/* 나쁜 예 — 포커스 표시 완전 제거 */
*:focus { outline: none; }
/* 좋은 예 — 키보드 사용 시에만 포커스 링 표시 */
:focus-visible {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
포커스 순서가 논리적이어야 한다. DOM 순서대로 Tab이 이동하니까, 시각적 순서와 DOM 순서가 일치해야 한다. CSS로 레이아웃을 뒤집어놓으면 Tab 순서가 꼬인다.
포커스 트랩. 모달이 열렸을 때 Tab이 모달 밖으로 나가면 안 된다. 모달 안에서만 포커스가 순환해야 한다. 이걸 구현 안 하면 모달 뒤의 보이지 않는 요소에 포커스가 갈 수 있다.
건너뛸 수 있어야 한다. 페이지 상단에 "본문으로 바로가기(Skip to content)" 링크를 넣으면, 키보드 사용자가 매번 내비게이션을 전부 Tab으로 지나갈 필요가 없다.
색상 대비
WCAG 2.2 기준으로 텍스트의 색상 대비 비율:
- 일반 텍스트: 최소 4.5:1 (AA 기준)
- 큰 텍스트(18pt 이상, 또는 14pt 볼드): 최소 3:1
- AAA 기준: 일반 텍스트 7:1, 큰 텍스트 4.5:1
실제로 체크해보면 의외로 안 지켜지고 있는 사이트가 많다. 회색 텍스트에 밝은 배경 조합이 특히 많이 걸린다. 디자인 트렌드상 옅은 회색이 "깔끔해 보여서" 많이 쓰이지만, 접근성 관점에서는 읽기 어려울 수 있다.
대비 비율 체크 도구:
- WebAIM Contrast Checker
- Chrome DevTools — Elements 패널에서 색상 선택기에 대비 비율이 표시된다
- Figma 플러그인 — Stark, A11y - Color Contrast Checker
자주 하는 실수들
이미지에 alt 빠뜨리기. 가장 흔한 실수다. 모든 <img>에 alt를 넣되, 장식용 이미지는 빈 alt(alt="")를 쓴다. 빈 alt를 쓰면 스크린 리더가 이미지를 건너뛴다. alt 속성 자체를 안 넣으면 스크린 리더가 파일명을 읽어버린다.
<!-- 정보 전달 이미지 -->
<img src="chart.png" alt="2025년 분기별 매출 그래프. 4분기에 30% 상승">
<!-- 장식용 이미지 -->
<img src="decorative-line.png" alt="">
폼 라벨 누락. <input>에 <label>을 연결하지 않는 경우가 많다. placeholder를 라벨 대신 쓰는 것도 접근성 측면에서 좋지 않다. placeholder는 입력을 시작하면 사라지니까.
<!-- 나쁜 예 -->
<input type="email" placeholder="이메일 주소">
<!-- 좋은 예 -->
<label for="email">이메일 주소</label>
<input type="email" id="email" placeholder="example@email.com">
링크 텍스트가 불명확. "여기를 클릭하세요", "더 보기" 같은 텍스트는 맥락 없이는 어디로 가는 링크인지 알 수 없다. 스크린 리더 사용자는 링크 목록만 모아서 탐색하기도 하는데, "여기를 클릭하세요"가 10개 나열되면 구분이 안 된다.
자동 재생 미디어. 갑자기 소리가 나는 건 모든 사용자에게 불쾌하지만, 스크린 리더 사용자에게는 특히 문제다. 스크린 리더의 음성 출력과 미디어 소리가 겹치니까. 자동 재생은 기본적으로 꺼야 한다.
움직이는 콘텐츠에 일시정지 기능이 없음. 자동 슬라이더, 마키 텍스트, 애니메이션 등은 일시정지/중지할 수 있어야 한다. WCAG 2.2.2 기준.
테스트 도구
코드를 다 짰으면 실제로 테스트를 해봐야 한다.
자동화 도구:
- Lighthouse — Chrome DevTools에 내장. 접근성 점수와 구체적인 개선 항목을 제시한다
- axe DevTools — 브라우저 확장 프로그램. Lighthouse보다 세밀한 검사. 자동으로 잡히는 문제와 수동 확인이 필요한 항목을 구분해준다
- eslint-plugin-jsx-a11y — JSX 코드의 접근성 문제를 빌드 타임에 잡아준다
자동화 도구가 잡을 수 있는 문제는 전체 접근성 이슈의 약 30~40% 정도다. 나머지는 수동 테스트가 필요하다.
수동 테스트:
- 키보드만으로 사이트 전체를 탐색해보기. Tab 순서가 자연스러운지, 모든 기능이 작동하는지
- 화면 확대(200%, 400%)에서 레이아웃이 깨지지 않는지
- 스크린 리더로 페이지를 들어보기 (VoiceOver, NVDA, JAWS)
스크린 리더 테스트가 가장 효과적이긴 한데, 처음 쓰면 조작법 자체가 익숙하지 않다. macOS의 VoiceOver(Cmd+F5로 켜짐)가 별도 설치 없이 바로 써볼 수 있어서 시작하기엔 좋다.
WCAG 2.2에서 새로 추가된 것들
2.2에서 몇 가지 기준이 추가됐다.
Focus Not Obscured (2.4.11, AA) — 포커스가 있는 요소가 다른 요소(sticky header, 쿠키 배너 등)에 가려지면 안 된다. 고정 헤더 때문에 Tab으로 이동한 요소가 안 보이는 경우가 꽤 있는데, 이제 명시적으로 기준이 생겼다.
Dragging Movements (2.5.7, AA) — 드래그 앤 드롭이 유일한 조작 방법이면 안 된다. 대안(버튼 클릭, 키보드 조작 등)을 제공해야 한다. 칸반 보드나 정렬 UI에 해당되는 항목이다.
Target Size (2.5.8, AA) — 클릭/터치 대상의 크기가 최소 24x24 CSS 픽셀이어야 한다. 모바일에서 작은 버튼을 누르기 어려운 문제를 해결하기 위한 기준이다.
접근성은 처음부터
프로젝트 마지막에 접근성을 "추가"하려고 하면 고통스럽다. 코드 구조를 바꿔야 하는 경우도 있고, 디자인 자체를 수정해야 할 수도 있다.
처음부터 시맨틱 HTML을 쓰고, 키보드 테스트를 하고, 색상 대비를 확인하는 게 훨씬 쉽다. 접근성은 기능을 추가하는 게 아니라, 웹 개발의 기본을 제대로 하는 것에 가깝다. HTML을 의미에 맞게 쓰고, 인터랙션을 표준에 맞게 구현하면 접근성의 상당 부분은 자동으로 충족된다.