적용 방법
접근 가능한 이름 계산
브라우저가 요소의 접근 가능한 이름(accessible name)을 어떤 순서로 정하는지, AccName 1.2 계산 단계와 우선순위, 실수하기 쉬운 경우를 정리합니다.
접근 가능한 이름이란
접근 가능한 이름(accessible name)은 보조기술이 요소를 부를 때 쓰는 이름입니다. 화면낭독기는 버튼에 포커스가 가면 “저장, 버튼”처럼 이름과 역할을 함께 읽고, 음성 인식 소프트웨어 사용자는 “저장 클릭”처럼 이름을 말해서 요소를 조작합니다. 링크 목록·폼 컨트롤 목록 같은 화면낭독기 탐색 기능도 이 이름으로 항목을 보여 줍니다.
이름은 개발자가 직접 하나의 값으로 지정하는 것이 아니라, 브라우저가 여러 출처(aria-labelledby, aria-label, <label>, alt, 요소 안의 텍스트, title 등)를 정해진 순서로 살펴 계산합니다. 이 규칙을 정의한 명세가 W3C의 Accessible Name and Description Computation 1.2(AccName)이고, HTML 요소별 세부 규칙은 HTML-AAM이 정합니다.
버튼·링크·폼 컨트롤처럼 사용자가 조작하는 요소에는 반드시 이름이 있어야 합니다(WCAG 4.1.2 이름, 역할, 값). 이름이 계산되는 원리는 이름·역할·값 문서와 접근성 트리 문서에서도 다룹니다.
이름과 설명은 따로 계산됩니다
같은 명세가 접근 가능한 설명(accessible description)도 정의합니다. 설명은 이름 뒤에 덧붙여 읽히는 보조 정보로, aria-describedby 등으로 지정합니다. 자세한 내용은 설명 연결하기 문서를 참고하세요.
이름이 정해지는 우선순위
한 요소에 이름 후보가 여러 개 있으면, 브라우저는 아래 표의 위쪽부터 확인해 처음으로 비어 있지 않은 값을 이름으로 씁니다. 아래 단계는 위 단계에 값이 있으면 무시됩니다.
| 순위 | 출처 | 예 | 비고 |
|---|---|---|---|
| 1 | aria-labelledby | <div role="dialog" aria-labelledby="dlg-title"> | 다른 요소의 텍스트를 참조합니다. 참조한 요소가 숨겨져 있어도 씁니다. |
| 2 | aria-label | <button aria-label="닫기">✕</button> | 문자열을 직접 지정합니다. 화면에는 보이지 않습니다. |
| 3 | HTML 네이티브 이름 | <label>, alt, <caption>, <legend>, <figcaption>, value(버튼형 input) | 요소마다 다르며 HTML-AAM이 정합니다. |
| 4 | 콘텐츠(하위 텍스트) | <button>저장</button> | 콘텐츠에서 이름을 가져오는 역할에만 적용됩니다. |
| 5 | title, placeholder | <input title="검색어"> | 마지막 수단입니다. 이것만으로 이름을 주지 않습니다. |
예를 들어 다음 버튼은 화면에 “장바구니”라고 보이지만, aria-label이 콘텐츠보다 앞서므로 이름은 “구매 목록 열기”가 됩니다. 화면 텍스트와 이름이 달라져 혼란을 주므로 이런 코드는 피합니다.
<button aria-label="구매 목록 열기">장바구니</button>
<!-- 이름: "구매 목록 열기" (콘텐츠 "장바구니"는 무시됨) --><button>장바구니</button>
<!-- 이름: "장바구니" -->먼저 HTML로 이름을 주세요
aria-label·aria-labelledby는 네이티브 수단이 없을 때 쓰는 보조 수단입니다. 입력 필드는 <label>, 이미지는 alt, 표는 <caption>, 그룹은 <legend>로 이름을 주는 것이 가장 견고합니다. ARIA 사용 규칙의 첫 번째 규칙과 같은 원칙입니다.
AccName 1.2 계산 단계
명세의 계산 과정은 요소(노드) 하나에 대해 아래 단계를 차례로 시도하고, 어떤 단계가 결과를 내면 그 값을 씁니다. 하위 요소의 텍스트를 모을 때는 같은 과정을 하위 요소마다 다시(재귀적으로) 적용합니다. 각 단계 이름은 명세의 표기를 따랐습니다.
- 숨김 확인(Hidden Not Referenced) — 요소가 숨겨져 있고(
display: none,hidden,aria-hidden="true"등)aria-labelledby·aria-describedby로 직접 참조된 경우가 아니면 빈 문자열을 돌려줍니다. - aria-labelledby(LabelledBy) —
aria-labelledby가 가리키는 요소들을 ID 순서대로 각각 계산해 공백으로 이어 붙입니다. 이미aria-labelledby를 따라온 중이면 이 단계는 건너뜁니다(참조는 한 번만 따라갑니다). - 포함된 컨트롤(Embedded Control) — 다른 요소의 이름을 계산하는 도중에 입력 필드·콤보박스·슬라이더 같은 컨트롤을 만나면, 그 컨트롤의 이름이 아니라 현재 값(입력된 텍스트, 선택된 옵션,
aria-valuetext또는aria-valuenow)을 씁니다. - aria-label(AriaLabel) — 공백만 있는 것이 아닌
aria-label값이 있으면 그 값을 씁니다. - 호스트 언어 레이블(Host Language Label) — HTML이 정한 네이티브 이름(
<label>,alt,<caption>,<legend>등)을 씁니다. 단,role="presentation"/role="none"으로 의미를 지운 요소에는 적용하지 않습니다. - 콘텐츠에서 이름(Name From Content) — 역할이 콘텐츠에서 이름을 가져오도록 허용하거나, 지금
aria-labelledby·<label>참조를 따라온 중이면 CSS 생성 콘텐츠(::before/::after)와 하위 노드의 결과를 차례로 모읍니다. - 텍스트 노드(Text Node) — 텍스트 노드면 그 글자를 돌려줍니다.
- 재귀적 콘텐츠 이름(Recursive Name From Content) — 이름을 계산하는 요소의 하위 요소이면, 자기 역할과 관계없이 그 안의 콘텐츠를 모읍니다.
- 툴팁 속성(Tooltip) — 위에서 아무 결과도 없을 때만
title같은 툴팁 속성을 씁니다.
마지막으로 각 단계의 결과는 공백으로 이어지고, 앞뒤 공백은 정리됩니다. display: block처럼 블록으로 표시되는 하위 요소 사이에는 공백이 들어가지만, 인라인 요소(<span>) 사이에는 공백이 자동으로 들어가지 않으므로 <span>장바</span><span>구니</span>는 “장바구니”가 됩니다.
<label for="flash">
<input type="checkbox" id="flash">
화면을 <input type="number" value="3" aria-label="깜빡일 횟수"> 번 깜빡이기
</label>
<!-- 체크박스 이름: "화면을 3 번 깜빡이기"
(포함된 숫자 입력 필드는 이름이 아니라 값 "3"이 들어감) -->콘텐츠에서 이름을 가져오는 역할
모든 요소가 안쪽 텍스트로 이름을 얻는 것은 아닙니다. WAI-ARIA 1.2는 콘텐츠에서 이름을 가져오는 역할을 정해 두었습니다. 대표적으로 button, link, checkbox, radio, switch, tab, menuitem, option, treeitem, heading, cell, columnheader, rowheader, gridcell, row, tooltip가 있습니다.
반대로 dialog, navigation, region, textbox, listbox, table, img 같은 역할은 콘텐츠에서 이름을 가져오지 않습니다. 이런 요소는 aria-labelledby, aria-label 또는 네이티브 레이블로 이름을 주어야 합니다.
<!-- 대화상자 안의 텍스트는 이름이 되지 않음 → 제목을 참조 -->
<div role="dialog" aria-modal="true" aria-labelledby="dlg-h">
<h2 id="dlg-h">주소 변경</h2>
...
</div>숨은 요소와 참조
계산 1단계에 따라 숨겨진 요소의 텍스트는 보통 이름에 들어가지 않습니다. 버튼 안의 장식 아이콘에 aria-hidden="true"를 주면 그 아이콘은 이름에서 빠집니다.
<button>
<svg aria-hidden="true" focusable="false">...</svg>
인쇄
</button>
<!-- 이름: "인쇄" -->예외는 aria-labelledby(또는 aria-describedby)가 숨겨진 요소를 직접 참조할 때입니다. 이 경우 참조된 요소와 그 하위 텍스트 전체가 이름에 들어갑니다. 화면에 보이지 않는 이름을 여러 곳에서 재사용할 때 쓸 수 있지만, 보이는 레이블이 따로 없는 상황이 되므로 꼭 필요한 경우에만 씁니다.
<span id="lbl-del" hidden>선택한 메일 삭제</span>
<button aria-labelledby="lbl-del">🗑</button>
<!-- 이름: "선택한 메일 삭제" (hidden이어도 직접 참조되었으므로 포함) -->주의할 점이 몇 가지 있습니다.
- 참조는 한 단계만 따라갑니다. 참조된 요소에 다시
aria-labelledby가 있어도 따라가지 않고, 그 요소의 콘텐츠(또는aria-label)를 씁니다. - 자기 자신을 참조할 수 있습니다.
aria-labelledby="btn-1 item-1"처럼 자신의 ID와 다른 요소 ID를 함께 나열하면 “더보기 상품명”처럼 이름을 조합할 수 있습니다. - 참조된 요소 안에서 숨겨진 하위 요소는 참조된 요소 자체가 보이는 경우 제외됩니다.
- 존재하지 않는 ID를 참조하면 그 ID는 무시됩니다. 모든 ID가 틀리면 다음 단계(aria-label 등)로 넘어갑니다.
<h3 id="p-101">무선 이어폰</h3>
<a id="more-101" href="/p/101" aria-labelledby="more-101 p-101">자세히 보기</a>
<!-- 이름: "자세히 보기 무선 이어폰" -->이름을 붙일 수 없는 역할
WAI-ARIA 1.2는 일부 역할에 이름 지정을 금지(name prohibited)합니다. 이런 요소에 aria-label·aria-labelledby를 주면 명세 위반이며, 브라우저나 화면낭독기가 무시하거나 일관성 없이 처리합니다.
이름 금지 역할: caption, code, deletion, emphasis, generic, insertion, paragraph, presentation/none, strong, subscript, superscript
실무에서 가장 흔한 실수는 역할이 없는 <div>·<span>(암묵적 역할 generic)에 aria-label을 붙이는 것입니다.
<div aria-label="공지 사항">
<p>점검 안내 ...</p>
</div><section aria-labelledby="notice-h">
<h2 id="notice-h">공지 사항</h2>
<p>점검 안내 ...</p>
</section>이름이 필요하면 역할부터 확인하세요
요소에 이름을 주고 싶다면, 그 요소가 이름이 의미 있는 역할(region, group, img, 위젯 역할 등)인지 먼저 확인합니다. 단순히 화면낭독기에 문장을 읽히려는 목적이라면 이름 대신 보이는 텍스트나 시각적으로 숨긴 텍스트를 씁니다.
title과 placeholder는 마지막 수단
title 속성은 다른 출처가 모두 비었을 때만 이름이 됩니다. 이름으로 쓰이지 않으면 대신 설명으로 쓰입니다. 하지만 마우스를 올려야만 보이고, 키보드·터치 사용자는 볼 수 없으며, 화면낭독기 설정에 따라 읽히지 않기도 하므로 유일한 이름 수단으로 쓰지 않습니다.
placeholder는 HTML-AAM에서 title보다도 뒤에 오는 이름 후보입니다. 입력을 시작하면 사라지고 대비가 낮은 경우가 많아 레이블 대신 쓰면 안 됩니다. 입력 형식 예시로만 쓰고, 이름은 <label>로 줍니다(폼 접근성 참고).
<input type="email" placeholder="이메일"><label for="em">이메일</label>
<input type="email" id="em" placeholder="name@example.com" autocomplete="email">보이는 레이블과 이름 일치 (Label in Name)
음성 인식 소프트웨어(Windows 음성 액세스, macOS·iOS 음성 제어, Dragon 등) 사용자는 화면에 보이는 글자를 말해서 버튼을 누릅니다. 그런데 접근 가능한 이름이 보이는 글자와 다르면 “검색 클릭”이라고 말해도 반응하지 않습니다. WCAG 2.5.3 이름에 레이블 포함(Label in Name)은 텍스트로 된 보이는 레이블이 있으면 접근 가능한 이름이 그 텍스트를 포함하도록 요구합니다(수준 A). 보이는 텍스트를 이름의 맨 앞에 두는 것이 가장 좋습니다.
<button aria-label="찾기 실행">검색</button><button aria-label="검색 - 상품 전체">검색</button>
<!-- 또는 aria-label 없이 <button>검색</button> -->- 추가 정보가 필요하면 이름을 바꾸기보다 설명(
aria-describedby)으로 덧붙이는 것이 안전합니다. - 아이콘만 있는 버튼은 보이는 텍스트 레이블이 없으므로 2.5.3의 대상이 아니지만, 아이콘이 흔히 불리는 이름(“닫기”, “메뉴”, “검색”)을 쓰면 음성 인식 사용자가 추측하기 쉽습니다.
- “더보기”처럼 같은 글자가 여러 번 나오면
aria-labelledby로 “더보기 무선 이어폰”처럼 뒤에 정보를 붙입니다.
이름 계산기
아래에서 예시를 고르면 해당 코드의 접근 가능한 이름과, 그 이름을 결정한 단계를 보여 줍니다. 두 번째 데모에서는 버튼의 속성을 직접 바꿔 가며 우선순위를 확인할 수 있습니다. 실제 브라우저의 계산 결과는 개발자 도구의 접근성 패널(Chrome·Edge의 Accessibility 탭, Firefox의 접근성 검사기)에서도 볼 수 있습니다.
예시 코드
이름:
결정 단계:
직접 바꿔 보기 — 아래 값을 바꾸면 버튼의 이름이 다시 계산됩니다.
외부 레이블 텍스트: 장바구니에 담기
계산된 이름:
결정 단계:
실시간 코드
데모의 한계
두 번째 데모의 계산은 이 페이지의 스크립트가 버튼 하나에 대해 우선순위만 단순화해 보여 주는 것입니다. 실제 브라우저는 숨김 여부, CSS 생성 콘텐츠, 하위 요소의 역할 등을 모두 반영하므로 결과가 다를 수 있습니다.
좋은 이름을 짓는 방법
- 짧고 구체적으로: “버튼”, “클릭”, “아이콘” 같은 말은 역할과 중복됩니다. 역할은 화면낭독기가 따로 읽으므로 이름에는 무엇을 하는지만 씁니다(“닫기”, “장바구니에 담기”).
- 문맥 없이도 구분되게: 링크 목록에서 “자세히 보기”가 열 개 나오면 구분할 수 없습니다. 대상 이름을 덧붙입니다(WCAG 2.4.4 링크 목적).
- 상태를 이름에 넣지 않기: “메뉴 열림”처럼 상태를 이름에 섞지 말고
aria-expanded,aria-pressed같은 상태 속성으로 표현합니다. 토글 버튼의 이름은 바꾸지 않는 것이 원칙입니다. - 보이는 텍스트와 일치시키기: 보이는 레이블이 있으면 이름이 그 텍스트로 시작하게 합니다.
- 언어 일관성: 페이지 언어(
lang)와 같은 언어로 씁니다. 영어 이름을 한국어 음성으로 읽으면 알아듣기 어렵습니다. - 번역 고려:
aria-label은 일부 자동 번역 도구가 번역하지 않습니다. 보이는 텍스트를aria-labelledby로 참조하면 번역과 이름이 함께 바뀝니다.
관련 문서
aria-label · aria-labelledby · aria-describedby 레퍼런스와 자주 하는 ARIA 실수를 함께 보세요. 직접 코드를 바꿔 보려면 실습실을 이용하세요.