WAI-ARIA 역할·속성·상태
한국어 해설 KO
Original Text EN
WAI-ARIA의 역할(Roles), 속성(Properties), 상태(States)를 이해하고, ARIA를 언제, 어떻게 사용해야 하는지 학습합니다.
Understand WAI-ARIA Roles, Properties, and States and learn when and how to use ARIA correctly.
학습 목표
ARIA의 역할, 속성, 상태의 차이를 설명할 수 있다
ARIA 사용의 첫 번째 규칙을 이해한다
주요 aria-* 속성(aria-label, aria-labelledby, aria-live 등)의 용도를 설명할 수 있다
aria-live 영역의 두 가지 값(polite, assertive)의 차이를 설명할 수 있다
Learning Objectives
Explain the differences between ARIA Roles, Properties, and States
Understand the First Rule of ARIA Use
Describe the purpose of key aria-* attributes
Distinguish between aria-live='polite' and aria-live='assertive'
ARIA란 무엇이고 무엇이 아닌가
What ARIA Is — and Isn't
WAI-ARIA(Accessible Rich Internet Applications)는 시맨틱 HTML만으로 표현하기 어려운 복잡한 UI 패턴(탭, 트리, 콤보박스, 라이브 영역 등)의 의미를 보조기술에 전달하는 W3C 표준입니다. ARIA는 접근성 트리에 노출되는 이름·역할·상태 정보를 바꿉니다.
WAI-ARIA (Accessible Rich Internet Applications) is the W3C standard for conveying the semantics of complex UI patterns — tabs, trees, comboboxes, live regions — that semantic HTML alone cannot express. ARIA changes the name, role, and state information exposed in the accessibility tree.
중요한 한계: ARIA는 의미만 바꿀 뿐 동작을 만들지 않습니다. `role="button"`을 붙여도 키보드 포커스나 Enter/Space 활성화는 생기지 않으며, 개발자가 tabindex와 키 이벤트를 직접 구현해야 합니다. 'ARIA는 약속이다 — 역할을 선언했으면 그 역할답게 동작하게 만들 책임이 따라온다'는 관점이 중요합니다. 잘못 쓴 ARIA는 없느니만 못합니다(No ARIA is better than bad ARIA).
A critical limitation: ARIA changes semantics only — it creates no behavior. Adding `role="button"` provides no keyboard focus and no Enter/Space activation; the developer must implement tabindex and key handling. Think of ARIA as a promise: declaring a role obligates you to make the element behave like that role. Badly used ARIA is worse than none — 'No ARIA is better than bad ARIA.'
역할·속성·상태
Roles, Properties, and States
ARIA의 3가지 핵심 개념: ① 역할(Roles) — 요소의 용도를 정의합니다(role="button", role="dialog", role="tablist", role="alert"). ② 속성(Properties) — 비교적 고정적인 추가 정보를 제공합니다(aria-label, aria-labelledby, aria-required). ③ 상태(States) — 상호작용에 따라 변하는 현재 조건을 나타냅니다(aria-expanded, aria-checked, aria-selected, aria-disabled).
Three core ARIA concepts: ① Roles define an element's purpose (role="button", role="dialog", role="tablist", role="alert"). ② Properties provide relatively fixed additional information (aria-label, aria-labelledby, aria-required). ③ States express current conditions that change with interaction (aria-expanded, aria-checked, aria-selected, aria-disabled).
속성과 상태의 구분 요령: 상태는 사용자 상호작용으로 자주 바뀌고(아코디언 열림/닫힘), 속성은 잘 바뀌지 않습니다(필수 여부). 상태를 선언했다면 JavaScript로 실제 상태 변화에 맞춰 값을 갱신해야 합니다 — aria-expanded를 true로 박아두고 갱신하지 않는 것이 흔한 결함입니다.
Telling properties from states: states change frequently through interaction (accordion open/closed); properties rarely change (whether a field is required). If you declare a state, you must update it with JavaScript as the real state changes — hardcoding aria-expanded="true" and never updating it is a classic defect.
ARIA 사용의 다섯 규칙
The Five Rules of ARIA Use
W3C가 정리한 ARIA 사용 규칙: ① 시맨틱 HTML로 가능하면 ARIA를 쓰지 않는다(제1규칙 — `<button>` 대신 `<div role="button">` 금지). ② 꼭 필요한 경우가 아니면 기본 시맨틱을 바꾸지 않는다(예: `<h2 role="tab">` 지양, 탭 안에 h2를 넣는 방식 선호). ③ 모든 인터랙티브 ARIA 컨트롤은 키보드로 사용 가능해야 한다.
The W3C's rules of ARIA use: ① Don't use ARIA if native HTML can do it (the First Rule — `<button>` over `<div role="button">`). ② Don't change native semantics unless you truly must (avoid `<h2 role="tab">`; prefer a heading inside the tab). ③ All interactive ARIA controls must be keyboard-usable.
④ 포커스 가능한 요소에 role="presentation"이나 aria-hidden="true"를 쓰지 않는다 — 포커스는 되는데 아무것도 낭독되지 않는 "유령 요소"가 됩니다. ⑤ 모든 인터랙티브 요소에는 접근 가능한 이름(accessible name)이 있어야 한다. 이 다섯 규칙은 ARIA 결함의 대부분을 예방합니다.
④ Never put role="presentation" or aria-hidden="true" on a focusable element — you create a 'ghost': focusable but announcing nothing. ⑤ Every interactive element needs an accessible name. These five rules prevent most ARIA defects.
이름 계산과 주요 속성
Name Computation and Key Attributes
접근 가능한 이름(accessible name)은 우선순위에 따라 계산됩니다: aria-labelledby > aria-label > 네이티브 라벨(`<label>`, alt, `<caption>`) > 콘텐츠 텍스트. aria-labelledby는 다른 요소의 텍스트를 참조하고(여러 id 나열 가능), aria-label은 문자열을 직접 제공하며, aria-describedby는 이름이 아닌 보조 설명을 연결합니다.
The accessible name is computed by priority: aria-labelledby > aria-label > native labeling (`<label>`, alt, `<caption>`) > content text. aria-labelledby references other elements' text (multiple ids allowed); aria-label supplies a string directly; aria-describedby attaches supplementary description — not the name.
그 밖의 주요 속성: aria-hidden="true"(보조기술에서 서브트리 숨김 — 시각적으로는 보임), aria-required(필수 입력), aria-invalid(유효성 오류), aria-current(현재 페이지/단계 표시). aria-label은 보이는 텍스트가 없는 아이콘 버튼 등에 쓰되, 보이는 라벨이 있으면 그 라벨을 이름에 포함해야 합니다(WCAG 2.5.3 Label in Name — 음성 제어 사용자).
Other key attributes: aria-hidden="true" (hides a subtree from AT while remaining visible), aria-required, aria-invalid, and aria-current (current page/step). Use aria-label for controls with no visible text, such as icon buttons — but when a visible label exists, it must be contained in the name (WCAG 2.5.3 Label in Name, for voice control users).
<!-- ❌ 이름 없는 아이콘 버튼: 스크린 리더는 "버튼"으로만 읽음 -->
<button><svg aria-hidden="true">…</svg></button>
<!-- ✅ aria-label로 이름 제공 (보이는 라벨이 있으면 그 텍스트를 포함할 것) -->
<button aria-label="검색">
<svg aria-hidden="true">…</svg>
</button><h2 id="ship-title">배송지 주소</h2>
<p id="ship-hint">도로명 주소를 입력하세요.</p>
<input aria-labelledby="ship-title" aria-describedby="ship-hint">라이브 영역
Live Regions
aria-live 영역은 동적으로 변경되는 콘텐츠(알림, 오류 메시지, 로딩 상태, 검색 결과 수)를 스크린리더가 자동으로 낭독하게 합니다. aria-live="polite"는 현재 낭독이 끝난 후 알리고, aria-live="assertive"는 즉시 중단하고 알립니다. assertive는 긴급 오류에만 사용하세요.
aria-live regions make screen readers announce dynamically changing content — notifications, error messages, loading states, result counts. aria-live="polite" waits for current speech to finish; aria-live="assertive" interrupts immediately. Reserve assertive for critical errors.
관련 역할: role="status"는 polite 라이브 영역, role="alert"는 assertive 라이브 영역과 동등합니다. 실무 요령: 라이브 영역은 페이지 로드 시점부터 DOM에 존재해야 안정적으로 동작하며(내용만 갱신), 요소 자체를 동적으로 삽입하면 낭독이 누락될 수 있습니다.
Related roles: role="status" is equivalent to a polite live region and role="alert" to an assertive one. Practical tip: live regions work reliably when the container exists in the DOM from page load and only its content updates — inserting the region element itself dynamically often drops announcements.
<!-- 폼 저장 결과 — 현재 낭독을 방해하지 않고 안내 -->
<div role="status" aria-live="polite">저장되었습니다.</div>
<!-- 긴급 오류 — assertive(role=alert)는 꼭 필요할 때만 -->
<div role="alert">세션이 만료되었습니다. 다시 로그인해주세요.</div>