ARIA 접근성 가이드

WCAG 2.2 · 4. 견고성 · 4.1 호환성

4.1.3 상태 메시지

Status Messages

검색 결과 수, "장바구니에 담았습니다", 진행 상황, 오류 개수 같은 상태 메시지는 포커스를 옮기지 않아도 보조 기술이 읽을 수 있도록 역할이나 속성으로 알려야 합니다.

수준 AAWCAG 2.1

한눈에 보기

성공 기준
4.1.3 상태 메시지
수준
수준 AA
원칙
4. 견고성
지침
4.1 호환성
도입
WCAG 2.1

요구 사항

마크업 언어로 구현한 콘텐츠에서 상태 메시지는 역할(role)이나 속성(property)으로 프로그램이 판별할 수 있어야 하며, 그래서 포커스를 받지 않아도 보조 기술이 사용자에게 전달할 수 있어야 합니다.

WCAG의 정의에 따르면 상태 메시지는 맥락의 변화가 아닌 콘텐츠 변화로서, 다음 정보를 사용자에게 알려 주는 것입니다.

  • 동작의 성공 또는 결과 — "장바구니에 담았습니다", "검색 결과 18건"
  • 애플리케이션의 대기 상태 — "불러오는 중…"
  • 프로세스의 진행 상황 — "업로드 60%"
  • 오류의 존재 — "입력 항목 중 2개에 오류가 있습니다"

적용 범위: 새 콘텐츠로 포커스를 옮기는 경우(예: 대화상자가 열리며 포커스가 이동)는 상태 메시지가 아니므로 이 기준의 대상이 아닙니다. 또한 페이지 이동, 새 창처럼 맥락이 바뀌는 경우도 대상이 아닙니다. 이 기준은 "포커스는 그대로인데 화면 어딘가에 메시지가 나타나는" 상황을 다룹니다.

왜 필요한가요

시각장애인은 화면 구석에 나타난 "저장되었습니다" 같은 메시지를 볼 수 없습니다. 메시지를 읽게 하려고 포커스를 옮기면 작업 흐름이 끊깁니다. 라이브 리전(live region)은 포커스를 그대로 둔 채 화면낭독기가 메시지를 읽게 해 줍니다. 화면 확대 사용자처럼 메시지가 시야 밖에 나타나는 사용자에게도 도움이 됩니다.

도움받는 사용자

  • 시각장애인(화면낭독기 사용자)
  • 저시력(화면 확대) 사용자
  • 인지장애 사용자

적용 방법

메시지의 성격에 맞는 라이브 리전 역할을 씁니다. 자세한 동작 원리는 라이브 리전 가이드와 알림 패턴을 참고하세요.

적용 방법
역할 / 속성암묵적 값쓰는 곳
statusaria-live="polite", aria-atomic="true"결과·성공 안내, 검색 결과 수, 저장 완료
alertaria-live="assertive", aria-atomic="true"즉시 알려야 하는 중요한 오류·경고
logaria-live="polite"채팅 메시지, 활동 기록처럼 순서대로 쌓이는 정보
progressbar—진행률(값은 aria-valuenow)
aria-live—위 역할이 맞지 않을 때 직접 지정

1. 결과 안내: role="status"

권장검색 결과 수
<form role="search">
  <label for="q">상품 검색</label>
  <input id="q" type="search">
  <button type="submit">검색</button>
</form>
<!-- 페이지를 처음 그릴 때부터 비어 있는 상태로 존재해야 합니다 -->
<p role="status" id="result-count"></p>
JavaScript
function showResults(items) {
  renderList(items);
  document.getElementById('result-count').textContent =
    '검색 결과 ' + items.length + '건';
}

2. 장바구니 담기 안내

권장HTML
<button type="button" id="add">장바구니 담기</button>
<div role="status" class="toast" id="toast"></div>
<script>
  document.getElementById('add').addEventListener('click', function () {
    document.getElementById('toast').textContent = '장바구니에 담았습니다. (총 3개)';
  });
</script>

3. 오류 알림: role="alert"

폼을 제출할 때 포커스를 오류 요약으로 옮기지 않는 방식이라면, 오류의 존재를 alert로 알립니다. 남용하면 다른 안내를 끊고 읽으므로 정말 중요한 메시지에만 씁니다.

HTML
<div role="alert" id="form-error"></div>
<!-- 제출 실패 시 -->
<!-- form-error.textContent = '입력 항목 중 2개에 오류가 있습니다.'; -->

4. 진행 상황과 대기 상태

진행 상황
<div role="progressbar" aria-label="파일 업로드"
     aria-valuemin="0" aria-valuemax="100" aria-valuenow="60"></div>
<p role="status" id="upload-msg">업로드 중… 60%</p>

진행률을 1%마다 알리면 너무 시끄러우므로, 상태 메시지는 25%·50%처럼 의미 있는 단계나 완료 시점에만 갱신합니다. 영역 전체를 다시 그리는 동안에는 aria-busy="true"로 중간 상태를 읽지 않게 할 수 있습니다.

라이브 리전이 동작하지 않는 흔한 원인

  • 라이브 리전 요소를 메시지와 동시에 DOM에 삽입하면 읽히지 않는 경우가 많습니다. 빈 컨테이너를 미리 두고 내용만 바꿉니다.
  • display:none이나 hidden 상태의 영역 안에서 바뀐 내용은 읽히지 않습니다.
  • 같은 문구를 다시 넣으면 변화로 인식하지 않을 수 있습니다. 내용을 비웠다가 다시 넣거나 문구를 조금 바꿉니다.

사례

눈에만 보이는 토스트 메시지

비권장HTML
<div class="toast">저장되었습니다.</div>

화면낭독기 사용자는 메시지가 나타난 것을 알 수 없습니다.

메시지와 함께 라이브 리전을 새로 삽입

비권장JavaScript
var el = document.createElement('div');
el.setAttribute('role', 'status');
el.textContent = '저장되었습니다.';
document.body.appendChild(el);   // 읽히지 않을 수 있음

미리 둔 라이브 리전에 내용만 갱신

권장JavaScript
// HTML: <div role="status" id="msg"></div>  (처음부터 존재)
document.getElementById('msg').textContent = '저장되었습니다.';

채팅 메시지 기록

권장HTML
<div role="log" aria-label="상담 대화">
  <p>상담원: 무엇을 도와드릴까요?</p>
  <!-- 새 메시지가 아래에 추가되면 순서대로 읽힘 -->
</div>

자주 하는 실수

  • "저장되었습니다", "장바구니에 담았습니다" 같은 메시지를 시각적으로만 표시하고 라이브 리전을 쓰지 않습니다.
  • 검색·필터 결과 수가 바뀌어도 보조 기술에 알리지 않습니다.
  • 라이브 리전 요소를 메시지와 동시에 생성해 화면낭독기가 읽지 못합니다.
  • 모든 안내에 role="alert"나 aria-live="assertive"를 써서 사용자의 작업을 계속 끊습니다.

검사 방법

  • 검색, 장바구니 담기, 저장, 업로드, 폼 제출 등 포커스 이동 없이 메시지가 나타나는 상황을 찾습니다.
  • 개발자 도구에서 메시지 컨테이너에 role="status", role="alert", role="log", aria-live 등이 있고, 메시지보다 먼저 DOM에 있는지 확인합니다.
  • 화면낭독기를 켠 채 동작을 실행해, 포커스가 그대로인 상태에서 메시지가 읽히는지 확인합니다.

관련 ARIA

다른 지침의 대응 항목

참고 자료