FEInterview Prep

Velog

99%의 개발자가 모르는 ARIA 속성

ARIA 의 첫 번째 규칙은 *ARIA 를 쓰지 마세요* — 의미론적 HTML 이 항상 우선. 그 위에 *역할(role) / 위젯 속성 / 라이브 영역 / 관계* 네 축으로 정리하면 헷갈리지 않는다.

2025-11-13·8분 읽기
브라우저
원문 보기 ↗

핵심 요약

ARIA 4축: (1) Rolebutton, dialog, tab, tabpanel, combobox, tree요소가 무엇인지. 랜드마크(banner/main/navigation/complementary), 문서 구조(article/list/table), 위젯(button/checkbox/...), 라이브 영역(alert/status/log) 으로 분류. (2) 위젯 속성aria-checked, aria-pressed, aria-expanded, aria-selected, aria-disabled, aria-required, aria-invalid, aria-valuenow/min/max. 상태가 변하면 반드시 동기화. (3) 라이브 영역 속성aria-live="polite|assertive", aria-atomic, aria-busy, aria-relevant — 동적 콘텐츠 알림의 긴급도. (4) 관계 속성aria-labelledby, aria-describedby, aria-controls, aria-owns, aria-activedescendant — 요소들을 의미적으로 연결. 가장 중요한 규칙은 변하지 않는다 — <button> 이 있으면 <div role="button"> 을 쓰지 말 것. ARIA 는 HTML 의 대체 가 아니라 보강.

ARIA 를 '장식적 a11y 속성 모음' 이 아니라 '(1) role: 요소가 무엇인가, (2) 위젯 속성: 사용자가 어떻게 상호작용하는가, (3) 라이브 영역: 동적 변화 알림, (4) 관계 속성: 요소 간 연결 — 이 네 축으로 보조 기술과 대화하는 표준 어휘' 로 본다. 첫 번째 규칙은 변치 않는다 — 기본 HTML 요소가 있으면 그것이 우선. ARIA 는 기본 HTML 로는 부족할 때만 의미를 보강한다.

시각적으로 멀쩡한 사이트스크린 리더 사용자에게는 사용 불가 인 경우가 흔하다.

  • <div onClick> 으로 만든 버튼은 키보드 포커스/Enter/Space 가 다 깨진 상태
  • 모달이 열렸는데 aria-modal="true" 가 없어 바깥 콘텐츠가 여전히 읽힌다
  • 폼 에러 메시지가 role="alert" 없이 조용히 화면에만 뜬다
  • 토글 버튼의 aria-pressed상태 변화 시 업데이트되지 않아 항상 false 로 읽힌다

전 세계 10억 명 이상이 보조 기술에 의존한다. 또한 키보드 사용성/SEO/구조적 명확성도 함께 좋아지므로, ARIA 를 정확히 쓰는 것은 추가 비용 이 아니라 기본 품질 이다.

학습 포인트

면접 답변으로 연결할 학습 포인트입니다.

First rule of ARIA: *don't use ARIA*

기본 HTML 요소가 있으면 그게 정답. ARIA 는 그 표준 요소로 표현 불가능할 때만 등장한다.

<!-- ❌ 키보드/포커스/Enter/Space 모두 직접 처리해야 함 -->
<div role="button" tabindex="0" onclick="submit()">Submit</div>

<!-- ✅ 모든 게 무료 — 키보드, AT, 포커스 링, 비활성, 폼 제출 -->
<button onclick="submit()">Submit</button>

ARIA 위젯 패턴 은 키보드 인터랙션을 모두 직접 구현 해야 동작한다. 가능하면 표준 요소로 가는 것이 접근성·유지보수·버그 모두 이익.

semantic HTMLroletabindex키보드 인터랙션
자주 하는 오해

디자인이 더 자유롭다는 이유로 <button> 대신 <div> 를 쓰는 것. 키보드 사용자/스크린 리더 사용자 모두를 떼어낸다.

상태 속성은 *반드시 동기화* 해야 의미가 있다

aria-expanded, aria-pressed, aria-checked, aria-selected상태가 변할 때 함께 업데이트 되어야 한다. 그렇지 않으면 처음 값 만 영원히 보고된다.

// ❌ 시각만 바뀌고 a11y 트리는 그대로
const [open, setOpen] = useState(false);
<button onClick={() => setOpen(!open)} aria-expanded="false">메뉴</button>

// ✅ 상태 변화에 따라 ARIA 도 동기화
<button onClick={() => setOpen(!open)} aria-expanded={open}>메뉴</button>

자동화 도구(axe, Lighthouse) 는 초기 렌더만 검사하므로 이 버그는 수동 테스트나 단위 테스트 로만 잡힌다.

aria-expandedaria-pressed상태 동기화controlled component
자주 하는 오해

정적 속성으로 박아두고 클래스만 토글 하는 것. 자동화 도구는 통과하지만 스크린 리더는 영원히 "접힘" 으로 읽는다.

라이브 영역으로 *동적 변화* 를 알려라

폼 에러, 검색 결과 갱신, 토스트 알림 같은 DOM 변화 는 보조 기술에 자동으로 전달되지 않는다. aria-live 또는 그에 해당하는 role 이 필요.

<!-- 폼 검증: 즉시 알림 -->
<span id="email-error" role="alert">올바른 이메일을 입력하세요</span>

<!-- 검색 결과: 적절한 시점에 알림 -->
<div id="results" aria-live="polite" aria-atomic="false">
  <span>12개 결과</span>
</div>

<!-- 로딩 표시 -->
<div role="status" aria-busy="true">불러오는 중...</div>

polite 는 사용자가 한가할 때, assertive 는 즉시 끼어든다. 남용하면 알림이 산만해 도리어 사용성을 해친다.

aria-liverole=alertaria-atomicaria-busy
자주 하는 오해

모든 변화aria-live="assertive" 를 박는 것. 사용자는 작업을 끊임없이 방해받는다.

읽는 순서

  1. 1이론

    WAI-ARIA Authoring Practices 의 Combobox, Dialog, Disclosure 패턴 세 가지를 정독.

  2. 2구현

    표준 <details>/<dialog> 로 다시 만들 수 있는지 먼저 시도하고, 안 되는 경우에만 ARIA 위젯 패턴으로 구현한다.

  3. 3실무

    axe DevTools + 키보드 only 탐색 + 스크린 리더(NVDA/VoiceOver) 로 본인 사이트의 핵심 페이지 3곳을 검증.

  4. 4설명

    팀에 'ARIA 의 첫 번째 규칙과 5가지 흔한 실수' 5분 발표.

면접 연결 질문

medium커스텀 토글 스위치를 만들 때 *접근성 측면* 에서 무엇을 확인해야 하나요?
힌트

[감점 답변] 'aria-label 만 붙이면 된다'. [좋은 답변] (1) <button role="switch" aria-checked={on}> 또는 <input type="checkbox" role="switch">키보드 포커스/Space 키 가 동작하는 표준 요소 위에. (2) aria-checked상태 변화에 따라 동기화. (3) 라벨은 <label> 또는 aria-labelledby. (4) 시각적 상태 외에 aria 라벨이 상태를 분명히 전달 — "on"/"off" 같은 텍스트.

hard모달 다이얼로그의 *접근성 체크리스트* 5개를 말해보세요.
힌트

[감점 답변] '역할만 dialog'. [좋은 답변] (1) role="dialog" + aria-modal="true". (2) 제목과 본문을 aria-labelledby/aria-describedby 로 연결. (3) 열릴 때 포커스를 다이얼로그 내부 첫 인터랙티브 요소로 이동. (4) 포커스 트랩 — 닫힐 때까지 외부로 못 나가도록 Tab 순환. (5) ESC 키 닫기 + 닫힐 때 원래 트리거 버튼 으로 포커스 복귀.

자기 점검

본인 사이트의 인터랙티브 요소 중 `<div>`/`<span>` 으로 만든 *버튼/체크박스* 가 있는지 점검하세요.
semantic HTMLtabindexkey handler
자주 하는 오해

'CSS 가 더 쉬워서'. 표준 요소도 appearance: none 으로 자유롭게 스타일 가능하다.

`aria-live="polite"` 와 `role="status"` 의 차이를 설명해보세요.
라이브 영역긴급도역할기본값
자주 하는 오해

'완전히 같다'. role="status"기본적으로 polite + atomic=true 를 가진 의미적 영역. 명시적으로 의도를 드러내고 싶을 때 role 을 쓴다.