(번역) 99%의 개발자가 모르는 ARIA 속성

TapK·3일 전
12
post-thumbnail

원문: https://dev.to/web_dev-usman/99-of-developers-dont-know-these-aria-attributes-exist-19j0?context=digest

2025년에 꼭 필요한 유일한 ARIA 속성 가이드

접근성은 더이상 선택 사항이 아닙니다. 요즘은 모두를 위해 동작하는 웹사이트를 만드는 것이 그 어느 때보다 쉬워졌습니다. ARIA 속성은 그 중심에 있고, 그 힘은 대부분의 개발자들이 생각하는 것보다 훨씬 큽니다.

이 글에서는 존재하는 모든 ARIA 속성을 하나하나 설명해 드리겠습니다. 인기 있는 속성만 다루는 게 아니라 완전하고 철저한 목록을 다룰 것입니다. 문서 속에서 먼지만 쌓여가는 생소한 사양이 아닙니다. 모던 웹 애플리케이션을 구축할 때 실제 문제를 해결하는 실용적인 도구들입니다.

더 진행하기 전에, 실용적인 예제가 담긴 CodePen 링크를 알려드립니다.

ARIA 속성이란 정확히 무엇인가요?

ARIA는 접근 가능한 리치 인터넷 애플리케이션(Accessible Rich Internet Applications)을 의미합니다. ARIA의 핵심은 스크린 리더와 같은 보조 기술과 소통할 수 있는 방법을 제공합니다. 사용자 정의 드롭다운이나 화려한 모달을 구축할 때, 코드는 그 요소가 무엇인지 알지만 스크린 리더는 알지 못합니다. ARIA는 그 간극을 메웁니다.

이렇게 생각해 보세요. divCSS를 사용해 아름다운 탭 인터페이스를 만들었습니다. 시각적으로는 완벽하지만, 스크린 리더를 사용하는 사람은 그것이 탭이라는 사실을 전혀 알 수 없습니다. 적절한 ARIA 속성을 추가하면, 갑자기 그 스크린 리더가 전체 상호작용 패턴을 이해하게 됩니다.

접근성이 실제로 중요한 이유

전 세계적으로 10억 명 이상의 사람들이 어떤 형태로든 장애를 가지고 있으며, 이는 전 세계 인구의 약 15~16%에 해당합니다. 많은 사람들이 웹을 사용하기 위해 스크린 리더, 음성 제어, 키보드 탐색 또는 기타 보조 기술에 의존합니다. 적절한 ARIA 구현이 없다면, 사이트가 겉보기에 멋질지 몰라도, 이 사용자들에게는 완전히 사용할 수 없는 사이트가 됩니다다.

접근성은 단순히 규정 준수나 소송 회피를 위한 것이 아닙니다(물론 그것들도 중요한 문제이긴 합니다). 접근성이 보장된 웹사이트는 더 나은 웹사이트입니다. 의미론적으로 더 명확하고, 키보드로 탐색하기 쉬우며, 구조가 더 잘 잡혀 있고, 종종 검색 엔진에서도 더 좋은 성과를 내기도 합니다.

ARIA의 첫 번째 규칙

이 방대한 목록을 깊이 있게 살펴보기 전에, 반드시 알아야 할 것이 있습니다. 의미론적 HTML이 항상 우선입니다.

<button> 요소가 존재할 때 <div role="button">을 사용하지 마십시오. HTML이 이미 그 역할을 수행하고 있다면 ARIA로 불필요한 작업을 반복하지 마십시오. 기본 요소는 접근성, 키보드 지원, 예상되는 동작이 내장되어 있습니다. ARIA는 HTML이 부족한 부분을 채우기 위한 것입니다.

존재하는 모든 ARIA 속성

자, 여기 완전한 목록이 있습니다. 각 속성을 언제, 왜 사용해야 하는지 이해할 수 있도록 용도별로 분류했습니다.

역할(Roles): 요소의 본질 정의

역할 속성은 보조 기술에 해당 요소가 정확히 어떤 유형인지 알려줍니다.

랜드마크 역할

페이지의 주요 섹션을 정의합니다.

  • role=“banner” 메인 헤더 영역
  • role=“navigation” 모든 네비게이션 메뉴
  • role=“main” 주요 콘텐츠
  • role=“complementary” 사이드바 같은 보조 콘텐츠
  • role=“contentinfo” 푸터 콘텐츠
  • role=“search” 검색 영역
  • role=“form” 양식 영역
  • role=“region” 식별할 가치가 있는 중요한 섹션

문서 구조 역할

콘텐츠가 어떻게 구성되었는지 설명합니다.

  • role=“article” 독립적인 구성 요소
  • role=“document” 문서 콘텐츠
  • role=“feed” 스크롤 가능한 기사 목록(소셜 미디어 피드 등)
  • role=“figure” 이미지, 다이어그램, 코드 스니펫
  • role=“img” 이미지 컨테이너
  • role=“list” 항목 목록
  • role=“listitem” 개별 목록 항목
  • role=“math” 수학 표기법
  • role=“none” 또는 role=“presentation” 의미적 의미 제거
  • role=“note” 각주 또는 부가 설명
  • role=“table” 표 형식 데이터
  • role=“row” 표 행
  • role=“rowgroup” 행 그룹 (thead, tbody, tfoot)
  • role=“cell” 표 셀
  • role=“columnheader” 열 머리글
  • role=“rowheader” 행 헤더
  • role=“separator” 시각적 구분선
  • role=“toolbar” 컨트롤이 있는 툴바
  • role=“tooltip” 컨텍스트 팝업 정보

위젯 역할

모든 인터랙티브 컴포넌트에 적용됩니다.

  • role=“button” 버튼
  • role=“checkbox” 체크박스
  • role=“radio” 라디오 버튼
  • role=“textbox” 텍스트 입력란
  • role=“searchbox” 검색 입력란
  • role=“switch” 토글 스위치
  • role=“slider” 범위 슬라이더
  • role=“spinbutton” 숫자 스피너
  • role=“combobox” 콤보 박스 (입력 + 드롭다운)
  • role=“listbox” 옵션 목록
  • role=“option” 개별 옵션
  • role=“menu” 메뉴 위젯
  • role=“menubar” 메뉴 바
  • role=“menuitem” 메뉴 항목
  • role=“menuitemcheckbox” 선택 가능한 메뉴 항목
  • role=“menuitemradio” 라디오 버튼 메뉴 항목
  • role=“tab” 탭 컨트롤
  • role=“tablist” 탭 컨테이너
  • role=“tabpanel” 탭 콘텐츠 패널
  • role=“tree” 트리 뷰
  • role=“treeitem” 트리 항목
  • role=“treegrid” 편집 가능한 트리 그리드
  • role=“grid” 대화형 그리드
  • role=“gridcell” 그리드 셀
  • role=“link” 링크
  • role=“progressbar” 진행률 표시기
  • role=“scrollbar” 스크롤바

복합(Composite) 역할

항목을 그룹화하기 위한 역할입니다.

  • role=“group” 일반 그룹
  • role=“radiogroup” 라디오 버튼 그룹
  • role=“rowgroup” 테이블의 행 그룹

라이브 영역(Live Region) 역할

동적으로 변경되는 콘텐츠를 위한 역할입니다.

  • role=“alert” 긴급 메시지
  • role=“log” 추가되는 로그
  • role=“marquee” 비필수 업데이트
  • role=“status” 상태 메시지
  • role=“timer” 타이머 및 카운트다운

Window 역할

모달 상호작용을 위한 역할입니다.

  • role=“dialog” 대화 상자
  • role=“alertdialog” 경고 대화 상자

추상 역할 (절대 사용하지 마세요)

command, composite, input, landmark, range, roletype, section, sectionhead, select, structure, widget, window 사양에는 존재하지만 직접 사용하기 위한 용도는 아닙니다.

위젯 속성: 상호작용 설명

사용자가 요소와 상호작용하는 방법을 알려줍니다.

  • aria-autocomplete=“none|inline|list|both” 자동 완성 동작
  • aria-checked=“true|false|mixed” 선택 상태
  • aria-disabled=“true|false” 비활성화 상태
  • aria-errormessage=“[ID]” 오류 메시지 링크
  • aria-expanded=“true|false|undefined” 확장 상태
  • aria-haspopup=“true|false|menu|listbox|tree|grid|dialog” 팝업 표시
  • aria-hidden=“true|false|undefined” 보조 기술에 대한 가시성
  • aria-invalid=“true|false|grammar|spelling” 유효성 검사 상태
  • aria-label=“[string]” 접근 가능한 레이블
  • aria-level=“[integer]” 계층적 수준
  • aria-modal=“true|false” 모달 상태
  • aria-multiline=“true|false” 다중 줄 입력
  • aria-multiselectable=“true|false” 다중 선택
  • aria-orientation=“horizontal|vertical|undefined” 방향
  • aria-placeholder=“[string]” 플레이스홀더 힌트
  • aria-pressed=“true|false|mixed|undefined” 토글 상태
  • aria-readonly=“true|false” 읽기 전용 상태
  • aria-required=“true|false” 필수 입력 필드
  • aria-selected=“true|false|undefined” 선택 상태
  • aria-sort=“ascending|descending|none|other” 정렬 방향
  • aria-valuemax=“[number]” 최댓값
  • aria-valuemin=“[number]” 최솟값
  • aria-valuenow=“[number]” 현재값
  • aria-valuetext=“[string]” 사람이 읽을 수 있는 값

라이브 영역 속성: 동적 콘텐츠 처리

사용자에게 변경 사항을 알리는 방식을 제어합니다.

  • aria-atomic=“true|false” 전체 영역 또는 변경 사항만 알림
  • aria-busy=“true|false” 로딩 상태
  • aria-live=“off|polite|assertive” 알림 긴급도
  • off 알림 없음
  • polite 유휴 시 알림
  • assertive 알림을 위해 중단
  • aria-relevant=“additions|removals|text|all” - 알릴 변경 사항 유형

드래그 앤 드롭 속성

  • aria-dropeffect=“copy|move|link|execute|popup|none” 드롭 효과 (ARIA 1.1에서 사용 중단됨)
  • aria-grabbed=“true|false|undefined” 드래그 상태 (ARIA 1.1에서 사용 중단됨)

관계 속성: 요소 연결

요소 간 의미적 관계를 생성합니다.

  • aria-activedescendant=“[ID]” 현재 활성화된 자식 요소
  • aria-colcount=“[integer]” 총 열 수
  • aria-colindex=“[integer]” 열 위치
  • aria-colspan=“[integer]” 병합된 열 수
  • aria-controls=“[ID list]” 제어되는 요소
  • aria-describedby=“[ID list]” 설명 출처
  • aria-details=“[ID]” 상세 설명
  • aria-flowto=“[ID list]” 읽기 순서 재정의
  • aria-labelledby=“[ID list]” 레이블 출처
  • aria-owns=“[ID list]” 소유된 자식 요소
  • aria-posinset=“[integer]” 세트 내 위치
  • aria-rowcount=“[integer]” 총 행 수
  • aria-rowindex=“[integer]” 행 위치
  • aria-rowspan=“[integer]” 행 스팬
  • aria-setsize=“[integer]” 세트 크기

전역 속성: 어디서나 작동

  • aria-atomic (위에서 다룸)
  • aria-busy (위에서 다룸)
  • aria-controls (위에서 다룸)
  • aria-current=“page|step|location|date|time|true|false” 현재 항목 표시기
  • aria-describedby (위에서 다룸)
  • aria-details (위에서 다룸)
  • aria-disabled (위에서 다룸)
  • aria-dropeffect (사용 중단됨)
  • aria-errormessage (위에서 다룸)
  • aria-flowto (위에서 다룸)
  • aria-grabbed (사용 중단됨)
  • aria-haspopup (위에서 다룸)
  • aria-hidden (위에서 다룸)
  • aria-invalid (위에서 다룸)
  • aria-keyshortcuts=“[string]” - 키보드 단축키
  • aria-label (위에서 다룸)
  • aria-labelledby (위에서 다룸)
  • aria-live (위에서 다룸)
  • aria-owns (위에서 다룸)
  • aria-relevant (위에서 다룸)
  • aria-roledescription=“[string]” 사용자 정의 역할 설명

매일 사용할 실용적인 예시

실제 코드에서 이 기능이 어떻게 작동하는지 살펴보겠습니다.

예시 1: 커스텀 토글 버튼

<div
  role="button"
  tabindex="0"
  aria-pressed="false"
  onclick="this.setAttribute('aria-pressed', this.getAttribute('aria-pressed') === 'false')"
>
  Dark Mode
</div>

버튼이 이미 있다면 div를 버튼으로 절대 사용하지 마세요

예시 2: 접근성 모달 대화상자

<div
  role="dialog"
  aria-modal="true"
  aria-labelledby="dialog-title"
  aria-describedby="dialog-desc"
>
  <h2 id="dialog-title">Delete Item?</h2>
  <p id="dialog-desc">This action cannot be undone.</p>
  <button>Delete</button>
  <button>Cancel</button>
</div>

예제 3: 양식(Form) 유효성 검사

<label for="email">Email Address</label>
<input
  type="email"
  id="email"
  aria-required="true"
  aria-invalid="true"
  aria-describedby="email-error"
/>
<span id="email-error" role="alert"> Please enter a valid email address </span>

예시 4: 확장 가능한 섹션

<button aria-expanded="false" aria-controls="content-panel">
  Show More Details
</button>
<div id="content-panel" hidden>Additional content here...</div>

예시 5: 실시간 검색 결과

<label for="search">Search Products</label>
<input
  id="search"
  type="search"
  aria-controls="results"
  aria-describedby="results-count"
/>
<div id="results" role="region" aria-live="polite">
  <span id="results-count">12 products found</span>
  <!-- 리스트 결과는 여기에 -->
</div>

접근성을 저해하는 실수

의미론적 HTML을 절대 대체하지 마세요

<!-- ❌ -->
<div role="button" onclick="submit()">Submit</div>
<!-- ✅ -->
<button onclick="submit()">Submit</button>

상태를 동기화 상태로 유지하세요

<!-- ❌ - 상태는 절대 업데이트되지 않습니다 -->
<button aria-expanded="false" onclick="toggle()">Menu</button>
<!-- ✅ - 상호작용을 통한 상태 업데이트 -->
<button
  aria-expanded="false"
  onclick="this.setAttribute('aria-expanded', this.getAttribute('aria-expanded') === 'false')"
>
  Menu
</button>

상호작용 가능한 콘텐츠를 절대 숨기지 마세요

<!-- ❌ - 버튼이 보조 기술에서 숨겨져 있습니다 -->
<button aria-hidden="true">Important Action</button>
<!-- ✅ - 데코레이티브(decorative) 요소만 숨기기 -->
<span aria-hidden="true"></span><button>Rate 5 Stars</button>

절대 일을 복잡하게 만들지 마세요

<!-- ❌ - 불필요한 aria-label -->
<h1 aria-label="“Welcome”">Welcome</h1>
<!-- ✅ - 텍스트 콘텐츠가 이미 접근 가능함 -->
<h1>Welcome</h1>

역할(role) 충돌을 피하십시오

<!-- ❌ - 의미가 혼란스러움 -->
<button role="heading">네비게이션 항목</button>
<!-- ✅ - 적절한 요소 사용 -->
<h2>네비게이션</h2>
<button>네비게이션 항목</button>

구현 테스트

ARIA를 추가한다고 해서 제대로 작동할 거라고 기대해서는 안 됩니다. 검증 방법은 다음과 같습니다.

  1. 브라우저 개발자 도구: Chrome과 Firefox에는 접근성 검사기가 내장되어 있습니다
  2. 스크린 리더: NVDA(Windows), JAWS(Windows), VoiceOver(Mac/iOS), TalkBack(Android)으로 테스트하세요
  3. 자동화 도구: axe DevTools, WAVE 또는 Lighthouse 감사 실행
  4. 키보드 탐색: Tab, Enter, Space, 화살표 키만으로 사이트 사용 시도
  5. 실제 사용자: 가장 신뢰할 수 있는 방법은 실제 보조 기술 사용자와 함께 테스트하는 것입니다

일반 시나리오에 대한 빠른 참조

라벨링 요소

  • aria-label 직접 라벨 텍스트
  • aria-labelledby 다른 요소의 텍스트 참조
  • aria-describedby 추가 설명

상호작용 상태

  • aria-expanded 확장 가능한 섹션용
  • aria-pressed 토글 버튼용
  • aria-checked 사용자 정의 체크박스용
  • aria-selected 선택된 옵션용

오류 처리

  • aria-invalid 유효하지 않은 필드 표시
  • aria-errormessage 오류 텍스트 링크
  • role="alert" 즉시 오류 알림

동적 콘텐츠

  • aria-live=“polite” 적절한 시점에 알림
  • aria-live=“assertive” 즉시 알림
  • aria-busy=“true” 로딩 중

탐색

  • aria-current=“page” 탐색 내 현재 페이지
  • aria-hidden=“true” 장식적 콘텐츠 숨김
  • aria-controls 콘텐츠로의 링크 트리거

마지막으로

이 방대한 목록을 보면 ARIA가 부담스러울 수 있습니다. 하지만 알아두셔야 할 점은 모든 속성을 외울 필요는 없다는 것입니다. aria-label, aria-expanded, aria-hidden, aria-live 같은 일반적인 속성부터 시작하세요. 프로젝트에서 필요할 때마다 나머지 속성을 배우면 됩니다.

진정으로 중요한 것은 ARIA의 존재 이유를 이해하는 것입니다. ARIA는 접근 방식에 관계없이 모든 사람이 웹을 사용할 수 있도록 하기 위해 존재합니다. 적절한 ARIA 속성을 추가할 때마다 여러분의 웹사이트는 더 많은 사람들에게 열립니다. 바로 이것이 웹이 추구해야 할 본질입니다.

그러니 작은 것부터 시작하세요. 현재 프로젝트에서 하나의 구성 요소를 선택하세요. 올바른 ARIA 속성을 추가하세요. 스크린 리더로 테스트해 보세요. 얼마나 빨리 익숙해지는지 놀라실 겁니다.

모두가 사용할 수 있을 때 웹은 더 나아집니다. 이제 여러분은 이를 실현할 도구를 갖췄습니다.

참고

profile
누구나 읽기 편한 글을 위해

2개의 댓글

comment-user-thumbnail
약 20시간 전

단순히 ARIA에 대해 훑고 가려다 '접근 방식에 관계없이 모든 사람이 웹을 사용할 수 있도록 하기 위해' 부분에서 생각이 많아졌습니다. 비타민보다는 진통제같은 속성인것 같네요. 좋은 글 감사합니다.

답글 달기
comment-user-thumbnail
약 18시간 전

프론트엔드 개발을 시작한지 어느덧 1년이 지났습니다. 자동완성 기능을 열심히 사용하다보니 aria 로 시작하는 추천 옵션이 항상 먼저 뜨더군요. 하지만 큰 의문을 품지 않고 무시하고 지내왔습니다.
글을 읽으며 과거의 제 자신을 반성하게되네요. 좋은 글 감사합니다.

답글 달기