C.W.K.
Stream
Lesson 03 of 04 · published

ARIA Baseline: 실제로 쓸 작은 실용 subset

~12 min · aria, screen-reader, labels, live-regions

Level 0Markup Novice
0 XP0/34 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"ARIA 의 첫 번째 규칙은: ARIA 쓰지 마. 두 번째 규칙은: 써야 할 때 이 작은 set 을 잘 써."

명세 자체가 피하라고 해

W3C 의 Using ARIA 문서가 문자 그대로 경고로 시작해: "이미 내장된 semantic 과 행동을 가진 native HTML element 를 쓸 수 있다면, element 의 용도를 바꾸고 ARIA role/state/property 를 추가해서 접근성을 만들지 말고 그 native 를 써라." ARIA 오용 대부분은 이미 맞는 semantic 을 가진 element 에 ARIA 를 더하는 데서 나와. <button aria-label="Submit">Submit</button>aria-label 이 조용히 redundant; 버튼의 텍스트 콘텐츠가 이미 접근성 이름.

그럼 ARIA 가 언제 제 값 해? 다섯 상황이 정당한 경우 90% 를 커버해.

1. 이름 없는 element 에 이름 주기

보이는 텍스트가 유용한 이름이 아닐 때 — icon-only 버튼, 돋보기 아이콘으로만 라벨링된 검색 입력, X 만 보이는 close 버튼 — 이름 줘.

  • aria-label="Close menu" — 접근성 이름이 이 속성에서 옴 (보이는 label 없을 때).
  • aria-labelledby="id-of-another-element" — 이름이 다른 element 안 텍스트에서 옴 (label 이 화면 다른 어딘가에 보일 때).

2. Element 묘사하기

Input 에 연결된 helper 텍스트, 힌트, 검증 메시지용:

  • aria-describedby="id" — description 가진 element 를 가리켜. Screen reader 가 이름 먼저, 그 다음 description 읽음. Password 힌트 ("최소 8 자, 숫자 하나"), 검증 에러, 포맷 가이드용.

3. 상태 전달하기

인터랙티브 element 의 상태가 중요하지만 native semantic 만으로는 명확하지 않을 때:

  • aria-expanded="true" | "false" — 메뉴, 아코디언, 드롭다운 여는 버튼.
  • aria-pressed="true" | "false" — 토글 버튼 (에디터의 bold/italic 떠올려).
  • aria-checked="true" | "false" | "mixed" — custom 체크박스 (mixed = indeterminate).
  • aria-selected="true" | "false" — custom 탭 리스트나 listbox 의 항목.
  • aria-disabled="true" — disabled 처럼 보이지만 여전히 focusable 하길 원하는 element (screen reader 사용자가 존재 알게). disabled 속성과 달라.

4. 폼 검증

  • aria-required="true" — native required 못 쓸 때만 필요 (custom 폼 컨트롤). Native HTML 입력에는 required 가 이걸 이미 설정.
  • aria-invalid="true" — 검증 실패 시 필드와 페어. Screen reader 가 필드 focus 받을 때 "invalid entry" announce. 에러 메시지 가리키는 aria-describedby 와 페어.

5. 동적 콘텐츠용 Live Region

사용자가 네비 안 하는데 콘텐츠가 업데이트될 때 (toast 알림, 저장 확인, 사용자 타이핑에 따라 필터링되는 검색 결과), screen reader 가 알아채지 못해 — 업데이트된 영역이 live region 이 아니면:

  • aria-live="polite" — screen reader 가 한가할 때 업데이트 announce. 대부분 알림의 기본 선택.
  • aria-live="assertive" — screen reader 가 말하던 거 interrupt. 중요한 메시지 (에러, 연결 끊김) 용. 절제해서 — 대문자 외침이야.
  • role="status" — polite live region 의 약자. 상태 메시지용.
  • role="alert" — assertive live region 의 약자. 에러용.

보조 기술에서 숨기기: aria-hidden="true"

보이지만 screen reader 가 건너뛰어야 할 때 — 장식용 아이콘, redundant 텍스트 — aria-hidden="true" 설정. 가장 흔한 케이스: 보이는 아이콘과 보이는 텍스트 라벨 둘 다 가진 버튼. 아이콘은 장식; 텍스트가 이름. 아이콘을 screen reader 에서 숨겨 "button, Settings" 전에 "image, settings" 가 announce 안 되게.

Focusable element 에 aria-hidden="true" 절대 놓지 마. Screen reader 사용자가 그들한테 숨겨진 element 로 tab 가면, 도착할 때 아무것도 안 들려. 좋게 봐도 헷갈리고, 나쁘게 보면 망가짐. 숨기면서 unfocusable 도 원하면 tabindex="-1" 이나 native hidden 속성도 더해.

만트라: Native 먼저, ARIA 다음

네가 쓰는 모든 ARIA 줄은 맞게 유지해야 할 줄이야. Native HTML element 는 맞는 semantic 을 공짜로 주고 브라우저가 자동으로 업데이트. 손으로 쓰는 ARIA 는 상태 바뀔 때마다 sync 유지 필요 — 모든 aria-expanded, 모든 aria-checked, 모든 aria-invalid 가 JavaScript 로 유지. 유지보수에서 native 가 매번 이김.

피파의 노트

cwkPippa 채팅 입력은 production 에 ARIA property 가 셋: textarea 의 aria-label="Message Pippa" (보이는 label 이 시각 디자인 위해 숨겨져서), 스트리밍 응답 중일 때 aria-busy="true" (screen reader 가 기다리는 거 알게), 새 메시지 announcement 영역의 aria-live="polite" (screen reader 사용자가 응답 떨어질 때 알려지게). 끝. 나머지는 다 native — <button>, <label>, <a>, markup 선택으로 정해지는 semantic role. 작은 ARIA 표면 = 상태가 sync 빠질 자리 적음.

Code

이름과 description, 정당한 ARIA·html
<!-- ARIA 가 제 값 하는 자리: icon-only 버튼 -->
<button aria-label="Close menu">
  <svg aria-hidden="true" width="24" height="24">...</svg>
</button>

<button aria-label="Send message" type="submit">
  <svg aria-hidden="true">...</svg>
</button>

<!-- aria-labelledby — 다른 보이는 element 에서 이름 가져오기 -->
<h2 id="section-prefs">Preferences</h2>
<section aria-labelledby="section-prefs">
  <p>Settings for theme, voice, and notifications.</p>
</section>

<!-- helper 텍스트용 aria-describedby -->
<label for="new-pw">New password</label>
<input id="new-pw" type="password"
       aria-describedby="pw-rules" required minlength="8" />
<small id="pw-rules">At least 8 characters, one number.</small>
aria-expanded — sync 유지해야 할 상태·html
<!-- Disclosure 버튼의 expand/collapse 상태 -->
<button aria-expanded="false"
        aria-controls="settings-panel"
        id="settings-toggle">
  Settings
</button>
<section id="settings-panel" hidden>
  ...
</section>

<script>
  const btn = document.getElementById('settings-toggle');
  const panel = document.getElementById('settings-panel');
  btn.addEventListener('click', () => {
    const isOpen = btn.getAttribute('aria-expanded') === 'true';
    btn.setAttribute('aria-expanded', String(!isOpen));
    panel.hidden = isOpen;
  });
</script>
Live region: polite vs assertive·html
<!-- 동적 업데이트용 live region -->
<form>
  <label for="email-x">Email</label>
  <input id="email-x" type="email" aria-describedby="email-error" />
  <p id="email-error" role="alert"></p>  <!-- assertive: 에러는 interrupt -->
</form>

<!-- Toast 알림: polite -->
<div role="status" aria-live="polite" id="toast"></div>

<script>
  function showToast(message) {
    document.getElementById('toast').textContent = message;
  }
  // showToast('Settings saved.') — screen reader 가 announce.
</script>

External links

Exercise

본 적 있는 icon-only 버튼 (close, settings, search) 골라서 세 버전 적기: (1) aria-label 으로, (2) 시각적으로 숨겨진 span 을 가리키는 aria-labelledby 로, (3) CSS 로 렌더된 보이는 텍스트로. 각자 Chrome DevTools → Accessibility 탭에서 열고 screen reader 이름이 맞는지 확인. 보너스: aria-live="polite" 가진 작은 toast component 만들기 — VoiceOver 가 업데이트 시 announce 해?
Hint
Screen reader 가 아무것도 announce 안 하면, live region 이 페이지 로드 시 비어 있었을 수 있어 (일부 브라우저는 announcement 시간에 존재 안 하던 live region 무시). 컨테이너를 초기 HTML 에 비어 있게 렌더하고, JavaScript 로 텍스트 업데이트.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.