기본 개념
ARIA 사용 5원칙
W3C 문서 Using ARIA가 제시하는 다섯 가지 규칙과 “잘못된 ARIA보다 ARIA가 없는 편이 낫다”는 원칙을 권장·비권장 코드로 정리합니다.
다섯 가지 규칙 한눈에 보기
| 규칙 | 요약 |
|---|---|
| 1. HTML을 먼저 쓴다 | 필요한 의미와 동작을 가진 네이티브 HTML 요소·속성이 있으면 그것을 씁니다. |
| 2. 네이티브 의미를 바꾸지 않는다 | 꼭 필요한 경우가 아니면 HTML 요소의 원래 의미를 ARIA로 덮어쓰지 않습니다. |
| 3. 키보드로 조작할 수 있어야 한다 | ARIA로 만든 모든 상호작용 컨트롤은 키보드로 쓸 수 있어야 합니다. |
| 4. 포커스 가능한 요소를 숨기지 않는다 | 포커스를 받는 요소에 role="presentation"이나 aria-hidden="true"를 쓰지 않습니다. |
| 5. 상호작용 요소에는 이름이 있어야 한다 | 모든 상호작용 요소는 접근 가능한 이름을 가져야 합니다. |
이 규칙들은 ARIA 명세 자체가 아니라, 명세를 올바르게 적용하기 위한 W3C의 실무 지침입니다. 하지만 검사 도구와 접근성 진단 대부분이 이 규칙을 기준으로 삼습니다.
규칙 1. 네이티브 HTML을 먼저 사용합니다
필요한 의미와 동작이 이미 내장된 네이티브 HTML 요소나 속성을 쓸 수 있다면, 다른 요소에 ARIA 역할·상태·속성을 붙여 용도를 바꾸는 대신 그 요소를 사용합니다.
네이티브 요소는 역할·이름 계산·포커스·키보드 동작·상태 전달을 브라우저가 모두 처리합니다. ARIA로 같은 것을 만들려면 이 모든 것을 직접 구현하고 유지해야 합니다.
<div role="checkbox" aria-checked="false" tabindex="0"
onclick="toggle(this)" onkeydown="onKey(event)">
약관에 동의합니다
</div><label>
<input type="checkbox" name="agree">
약관에 동의합니다
</label>대표적인 대응 관계는 다음과 같습니다.
| ARIA로 만들기 전에 | 먼저 쓸 HTML |
|---|---|
button | <button> |
link | <a href> |
checkbox, radio | <input type="checkbox">, <input type="radio"> |
heading + aria-level | <h1> ~ <h6> |
navigation, main, search | <nav>, <main>, <search> |
dialog + aria-modal | <dialog> + showModal() |
slider | <input type="range"> |
aria-required, aria-disabled | required, disabled |
aria-expanded로 만든 단순 펼침 | <details> / <summary> |
ARIA가 필요한 경우
Using ARIA는 다음 경우에 ARIA를 쓰라고 안내합니다. ① 디자인 요구 때문에 네이티브 요소를 원하는 모양으로 꾸밀 수 없을 때, ② 필요한 기능이 HTML에 아직 없을 때(탭, 트리, 콤보박스 자동완성 등), ③ 기능은 있지만 브라우저·보조기술 지원이 부족할 때.
규칙 2. 네이티브 의미를 바꾸지 않습니다
정말 필요한 경우가 아니라면 네이티브 의미를 바꾸지 않습니다.
role을 붙이면 요소의 원래 역할은 사라집니다. 제목에 role="tab"을 붙이면 제목 목록으로 이동하는 사용자는 그 제목을 찾을 수 없게 됩니다. 의미를 덧붙이고 싶다면 요소를 감싸거나 안에 넣습니다.
<h2 role="tab">배송 안내</h2><div role="tab">
<h2>배송 안내</h2>
</div><a href="#" role="button" onclick="openMenu()">메뉴</a><button type="button" aria-expanded="false" aria-controls="m1">메뉴</button>요소마다 허용되는 역할은 ARIA in HTML 명세가 정합니다. 자세한 표는 HTML과 ARIA 매핑을 참고하세요.
규칙 3. 모든 상호작용 ARIA 컨트롤은 키보드로 조작할 수 있어야 합니다
위젯을 만든다면 사용자가 마우스로 할 수 있는 모든 동작을 키보드로도 할 수 있어야 합니다.
role="button"을 붙였다면 Tab으로 포커스가 가고 Enter와 Space로 실행되어야 합니다. role="tablist"라면 화살표 키로 탭을 이동할 수 있어야 합니다. 역할마다 기대되는 키보드 동작은 APG와 각 패턴 문서에 정리되어 있습니다.
<span role="button" onclick="save()">저장</span><span role="button" tabindex="0" id="save">저장</span>
<script>
const el = document.getElementById('save');
el.addEventListener('click', save);
el.addEventListener('keydown', (e) => {
if (e.key === 'Enter') save();
if (e.key === ' ') { e.preventDefault(); }
});
el.addEventListener('keyup', (e) => {
if (e.key === ' ') save();
});
</script>자세한 내용은 키보드와 포커스 관리를 참고하세요.
규칙 4. 포커스 가능한 요소에 role="presentation"이나 aria-hidden="true"를 쓰지 않습니다
aria-hidden이 true인 요소는 접근성 트리에서 빠지지만, 키보드 포커스는 여전히 받습니다. 사용자는 Tab을 눌렀는데 아무것도 읽히지 않는 “유령 포커스”를 만나게 됩니다. role="presentation"(또는 none)도 포커스 가능한 요소에서는 무시되거나 역할 정보를 잃게 만듭니다.
<button type="button" aria-hidden="true">닫기</button>
<div aria-hidden="true">
<a href="/event">이벤트 보기</a>
</div><!-- 장식 요소만 숨깁니다 -->
<button type="button">
<svg aria-hidden="true" focusable="false">…</svg>
닫기
</button>
<!-- 영역 전체를 비활성화하려면 inert -->
<div inert>
<a href="/event">이벤트 보기</a>
</div>모달 뒤 배경을 숨길 때
모달 대화상자를 열고 배경에 aria-hidden="true"를 붙일 때는 배경의 포커스 가능한 요소에도 포커스가 가지 않게 해야 합니다. inert 속성이나 네이티브 <dialog>의 showModal()을 쓰면 두 가지가 함께 처리됩니다.
규칙 5. 모든 상호작용 요소에는 접근 가능한 이름이 있어야 합니다
버튼, 링크, 입력 필드, 직접 만든 위젯처럼 조작할 수 있는 요소에는 이름이 있어야 합니다. 이름이 없으면 사용자는 “버튼”, “편집창”이라는 역할만 듣고 무엇을 하는 요소인지 알 수 없습니다.
<span>사용자 이름</span>
<input type="text" name="user">
<a href="/cart"><img src="cart.svg"></a><label for="user">사용자 이름</label>
<input type="text" id="user" name="user">
<a href="/cart"><img src="cart.svg" alt="장바구니"></a>이름을 붙이는 방법(<label>, aria-labelledby, aria-label)과 우선순위는 접근 가능한 이름에서 다룹니다.
No ARIA is better than bad ARIA
APG의 “Read Me First”는 “잘못된 ARIA보다 ARIA가 없는 편이 낫다(No ARIA is better than bad ARIA)”고 강조합니다. ARIA는 브라우저가 알려 주는 정보를 덮어쓰기 때문에, 잘못 쓰면 아무것도 하지 않았을 때보다 상황이 나빠집니다.
<button role="link">처럼 역할을 바꾸면 사용자는 링크라고 듣고 이동을 기대하지만 실제로는 동작이 실행됩니다.aria-expanded="false"를 고정해 두면 메뉴가 열려 있어도 “축소됨”이라고 잘못 안내합니다.role="menu"를 사이트 내비게이션에 붙이면 화면낭독기가 애플리케이션 메뉴 모드로 바뀌어, 일반 링크 탐색 방식이 통하지 않습니다.aria-label로 화면 글자와 다른 이름을 붙이면 음성 인식 사용자가 보이는 글자로 요소를 부를 수 없습니다.
실제로 WebAIM이 매년 발표하는 “WebAIM Million” 조사에서도 ARIA를 사용한 페이지가 사용하지 않은 페이지보다 평균적으로 더 많은 접근성 오류가 발견되는 경향이 반복해서 보고되고 있습니다. ARIA를 많이 쓴다고 접근성이 좋아지는 것이 아니라, 필요한 곳에 정확히 써야 합니다.
ARIA를 쓰기 전 자문할 것
- 같은 일을 하는 HTML 요소나 속성이 있는가?
- 이 역할이 약속하는 키보드 동작과 상태 변화를 모두 구현했는가?
- 값을 화면 상태와 항상 함께 갱신하는가?
- 실제 화면낭독기로 들어 보았는가?
자주 하는 실수는 자주 하는 ARIA 실수에 모아 두었습니다.