본문으로 건너뛰기
개발 머꼬
개발 노트HTML
hohyeon.dev16

aria-live를 붙였는데 스크린리더가 아무것도 읽지 않은 이유

  • #Accessibility
  • #Engineering Note
  • #HTML

문제 발생

검색 결과 개수와 "저장되었습니다" 메시지를 화면에 잘 띄웠는데, 스크린리더 사용자에게는 아무 일도 일어나지 않은 것과 같았습니다. 화면은 바뀌었지만 읽어주지 않았습니다.

메시지를 통째로 새로 만들어 붙이는 방식이었습니다.

const box = document.createElement("p");
box.setAttribute("aria-live", "polite");
box.textContent = "저장되었습니다.";
document.body.append(box);   // 이래도 안 읽힘

원인 분석

라이브 리전에는 순서 규칙이 있습니다. MDN이 명시합니다 — 보조기술은 일반적으로 라이브 리전 내용의 동적인 변화만 알립니다. aria-live 속성이나 라이브 리전 role을 붙이는 것은 변화가 일어나기 전에 그 속성을 추가했을 때만 동작합니다. 원래 마크업에 있거나, 미리 JavaScript로 넣어두어야 합니다. 그리고 권장 순서를 이렇게 적습니다 — 빈 라이브 리전으로 시작한 다음, 별개의 단계로 그 안의 내용을 바꿉니다.

위 코드는 속성과 내용을 동시에 붙였습니다. 브라우저 입장에서는 "라이브 리전이 새로 생겼다"일 뿐 "라이브 리전의 내용이 바뀌었다"가 아닙니다.

값 선택도 중요합니다. polite는 사용자가 말을 멈춘 틈에 읽어주고, assertive는 읽고 있던 것을 끊습니다. MDN은 assertive를 두고 즉각적인 주의가 반드시 필요한 시급하고 치명적인 알림에만 써야 하며, 극도로 성가시고 방해가 될 수 있으므로 아껴 써야 한다고 적습니다.

해결 방안

  1. 빈 컨테이너를 먼저 렌더하고, 나중에 내용만 채웁니다.
<p id="status" role="status" aria-live="polite"></p>
document.getElementById("status").textContent = "저장되었습니다.";

React처럼 선언형 UI에서도 같습니다 — 조건부로 요소 자체를 만들지 말고, 요소는 항상 두고 내용을 비웁니다.

<p role="status" aria-live="polite">{message}</p>
  1. 기본은 polite입니다. 검색 결과 개수, 저장 완료, 로딩 종료 같은 것은 전부 여기 해당합니다.

  2. role을 함께 씁니다. 각 role에는 암묵적 aria-live 값이 있습니다.

role암묵적 값용도
statuspolite상태 메시지
alertassertive오류·경고
logpolite채팅, 로그
timeroff타이머

statuslog에는 호환성을 위해 aria-live="polite"를 중복해 붙이는 것이 권장되지만, alert는 다릅니다 — MDN이 지적하듯 초기 마크업에 있어도 알려주고, aria-live="assertive"를 중복하면 브라우저·보조기술 조합에 따라 두 번 읽힐 수 있습니다.

  1. 전체를 읽어야 하면 aria-atomic="true"입니다. 일부만 바뀌어도 리전 전체를 읽습니다. 시계처럼 조각이 나뉜 표시에 필요합니다.
<div role="timer" aria-live="polite" aria-atomic="true">
  <span id="h">12</span>:<span id="m">34</span>
</div>

aria-atomic이 없으면 바뀐 34만 읽힙니다.

  1. 무엇을 변화로 볼지는 aria-relevant입니다. 기본값은 additions text입니다. 참가자가 나가는 것도 알려야 하는 목록이라면 removals를 추가합니다.
<ul aria-live="polite" aria-relevant="additions removals"></ul>
  1. off는 "알리지 않는다"가 아닙니다. MDN이 직관에 반한다고 표현합니다 — off인 요소의 변화는 포커스가 그 요소 안이나 위에 있을 때만 알려지도록 되어 있습니다.

  2. 과하게 쓰지 않습니다. 모든 변화를 읽어주면 아무것도 못 듣는 것과 같습니다. 사용자가 결과를 알아야 하는 지점에만 둡니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.