도입 스토리
"영어 원문 인용이 몇 군데 있는데, 스크린리더가 한국어 발음으로 읽어버려요." 김개발이 말했습니다.
NVDA가 "Web Content Accessibility Guidelines"을 한국어 억양으로 발음했습니다. 완전히 다른 소리였습니다.
"두 가지 문제예요." 박멘토가 설명했습니다. "첫째, 페이지 언어(lang="ko")는 맞게 설정되어 있지만, 인용된 영어 구절에 lang="en"이 없어요. 둘째, 언어만이 아니라 예측 가능성 문제도 있어요 — 어떤 페이지에서는 Select 선택 시 자동으로 페이지가 이동하거든요."
핵심 개념 설명
페이지 언어 — WCAG 3.1.1
<html> 태그에 lang 속성으로 페이지 기본 언어를 지정해야 합니다.
<!-- 한국어 페이지 --><!DOCTYPE html><html lang="ko"><head>...</head><body>...</body></html><!-- 영어 페이지 --><html lang="en"><!-- 언어 코드 예시 --><!-- ko: 한국어, en: 영어, ja: 일본어, zh: 중국어, fr: 프랑스어 -->
lang 속성이 없으면 스크린리더가 기본 언어(주로 영어)로 읽습니다. 한국어 콘텐츠를 영어 발음으로 읽으면 알아들을 수 없습니다.
부분 언어 — WCAG 3.1.2
페이지 중간에 다른 언어가 있으면 해당 요소에 lang을 지정합니다.
<p> 웹 접근성 국제 표준인 <span lang="en">Web Content Accessibility Guidelines</span>은 W3C가 발행합니다.</p><blockquote lang="en" cite="https://www.w3.org/TR/WCAG22/"> <p>"The power of the Web is in its universality."</p></blockquote><!-- 올바른 언어 코드 사용 --><p>이 서비스는 <span lang="ja">日本語</span>도 지원합니다.</p>
예측 가능성 — WCAG 3.2.1, 3.2.2
사용자가 예상하지 못한 동작이 발생하면 안 됩니다.
포커스 획득 시 자동 동작 금지 (WCAG 3.2.1):
<!-- 잘못된 예: 포커스만으로 팝업 열림 --><input type="text" onfocus="openCalendar()"><!-- 올바른 예: 사용자 의도적 행동(클릭/Enter)으로 열기 --><div class="date-field"> <input type="text" id="date" readonly> <button type="button" aria-label="날짜 선택기 열기" onclick="openCalendar()" > 📅 </button></div>
입력 시 자동 제출 금지 (WCAG 3.2.2):
<!-- 잘못된 예: 선택 즉시 페이지 이동 --><select onchange="window.location.href=this.value"> <option value="/home">홈</option> <option value="/about">소개</option></select><!-- 올바른 예: 이동 버튼 별도 제공 --><div> <label for="page-nav">페이지 이동</label> <select id="page-nav"> <option value="/home">홈</option> <option value="/about">소개</option> </select> <button type="button" onclick="window.location.href=document.getElementById('page-nav').value" > 이동 </button></div>
일관성 — WCAG 3.2.3, 3.2.4
- WCAG 3.2.3: 여러 페이지에서 반복되는 내비게이션은 같은 순서여야 합니다.
- WCAG 3.2.4: 같은 기능을 하는 컴포넌트는 일관된 이름을 써야 합니다.
<!-- 잘못된 예: 페이지마다 다른 메뉴 순서 --><!-- 홈 페이지: 홈 | 소개 | 제품 | 연락처 --><!-- 소개 페이지: 소개 | 홈 | 연락처 | 제품 --><!-- 잘못된 예: 같은 기능, 다른 이름 --><button>검색</button> <!-- A 페이지 --><button>찾기</button> <!-- B 페이지 --><button>Search</button> <!-- C 페이지 -->
같은 기능은 같은 레이블을 사용합니다. 스크린리더 사용자는 기억으로 사이트를 탐색하므로, 일관성이 매우 중요합니다.
단계별 실습
따라하기: 페이지 언어 확인하기
Chrome DevTools 콘솔에서 확인합니다.
// 페이지 언어 확인console.log('페이지 언어:', document.documentElement.lang);// lang 속성 없는 요소 찾기 (외국어 텍스트일 수 있는 요소)document.querySelectorAll('[lang]').forEach(el => { console.log('언어 지정:', el.lang, el.textContent.substring(0, 30));});
변형하기: 자동 제출 폼 개선하기
Select 기반 내비게이션에 이동 버튼을 추가합니다.
// 기존 onchange 내비게이션을 접근성 있게 변환function makeSelectNavAccessible(selectEl) { // onchange 핸들러 제거 selectEl.removeAttribute('onchange'); // 이동 버튼 생성 const btn = document.createElement('button'); btn.type = 'button'; btn.textContent = '이동'; btn.addEventListener('click', () => { window.location.href = selectEl.value; }); // Select 다음에 버튼 삽입 selectEl.parentNode.insertBefore(btn, selectEl.nextSibling);}
응용하기: 언어 일관성 감사
여러 페이지를 탐색하며 내비게이션 순서와 버튼 이름이 일관되는지 확인합니다.
정리와 확인
핵심 내용 요약
lang속성(WCAG 3.1.1):<html lang="ko">— 스크린리더 발음 정확도- 부분 언어(WCAG 3.1.2): 인용된 외국어에
<span lang="en">지정 - 자동 동작 금지(WCAG 3.2.1/3.2.2): 포커스/입력으로 자동 페이지 이동 금지
- 일관성(WCAG 3.2.3/3.2.4): 메뉴 순서와 컴포넌트 이름 일관성 유지
확인 문제
문제 1. <html lang="ko"> 없이 영어 스크린리더 사용자가 한국어 페이지를 방문하면?
스크린리더가 기본 언어(영어)로 한국어 텍스트를 발음하려 합니다.
완전히 알아들을 수 없는 발음이 됩니다.
문제 2. <select onchange="location.href=this.value">가 접근성 문제인 이유는?
키보드로 화살표 키를 눌러 옵션을 탐색하는 중에 onchange가 발생합니다.
원하는 옵션에 도달하기 전에 페이지가 이동해버려 키보드 사용자가 선택할 수 없습니다.
다음 챕터에서는 입력 도움과 오류 메시지를 다룹니다. 폼은 가장 많은 접근성 오류가 발생하는 곳입니다. 레이블, 힌트, 오류 메시지를 제대로 연결하는 방법을 알아봅니다.