aria-label과 텍스트 콘텐츠

Frontend

aria-label을 쓰다 보면 헷갈리는 부분이 있다. 텍스트 콘텐츠와 aria-label을 함께 넣었을 때, 스크린 리더가 둘 다 읽을지 아니면 하나만 읽을지 애매한 것이다.

 

예를 들어 버튼에 "삭제"라고 써있고 aria-label="이 리뷰 삭제하기"를 추가하면 "이 리뷰 삭제하기 삭제"로 읽힐까? 아니면 둘 중 하나만 읽힐까?

 

정답은 요소마다 다르다. 어떤 요소는 aria-label이 텍스트를 완전히 대체하고, 어떤 요소는 텍스트와 함께 읽힌다.

aria-label이 텍스트를 대체하는 요소들

상호작용하는 요소들

버튼, 링크, 입력 필드처럼 사용자가 클릭하거나 입력하는 요소들은 aria-label이 기존 텍스트를 대체한다.

<button aria-label="이 리뷰 삭제하기">삭제</button>
<!-- 읽힘: "이 리뷰 삭제하기" -->

<a href="/edit" aria-label="프로필 수정 페이지로 이동">수정</a>
<!-- 읽힘: "프로필 수정 페이지로 이동" -->

여기에 해당하는 요소: <a>, <button>, <input>, <select>, <textarea>

 

페이지 구조 요소들

헤더, 네비게이션, 섹션 같은 구조를 나타내는 요소들도 마찬가지다.

<nav aria-label="메인 네비게이션">
  <ul>...</ul>
</nav>
<!-- 읽힘: "메인 네비게이션" -->

여기에 해당하는 요소: <header>, <nav>, <main>, <footer>, <aside>, <section>, <form>, <fieldset>, <legend>, <iframe>, <img>

 

이런 요소들은 "무엇을 하는가"가 중요하기 때문에 aria-label로 더 구체적인 설명을 제공하면 기존 텍스트는 무시된다.

 

aria-label과 텍스트가 함께 읽히는 요소들

반면 제목이나 문단처럼 콘텐츠를 담는 요소들은 다르게 동작한다.

<h2 aria-label="중요 공지:">새로운 기능 안내</h2>
<!-- 읽힘: "중요 공지: 새로운 기능 안내" -->

<p aria-label="참고:">이 기능은 베타 버전입니다.</p>
<!-- 읽힘: "참고: 이 기능은 베타 버전입니다." -->

여기에 해당하는 요소: <h1>~<h6>, <p>, <li>, <dt>, <dd>, <span>, <div> (role이 없을 때)

 

이런 요소들은 "무엇을 담고 있는가"가 중요하다. 콘텐츠 자체가 의미이기 때문에 aria-label은 추가 정보로만 작용한다.

 

실제 사용 예시

아이콘만 있는 버튼

<button aria-label="메뉴 열기">
  <svg>...</svg>
</button>

아이콘만 있고 텍스트가 없는 버튼에서 유용하다.

 

맥락을 추가해야 하는 링크

페이지에 "삭제" 링크가 여러 개 있으면 스크린 리더 사용자는 어떤 걸 삭제하는지 구분하기 어렵다.

<a href="/delete" aria-label="댓글 삭제">삭제</a>

이렇게 하면 "댓글 삭제"로 읽혀서 명확해진다.

 

제목에 강조 추가

<h2 aria-label="필독:">공지사항</h2>
<!-- 읽힘: "필독: 공지사항" -->

제목에 추가 맥락을 넣고 싶을 때 사용할 수 있다.

 

주의해야 할 점

우선순위

aria-labelledby와 aria-label을 함께 쓰면 aria-labelledby가 우선된다.

<button aria-label="무시됨" aria-labelledby="label-id">버튼</button>
<span id="label-id">실제로 읽힘</span>

 

img 태그의 특수성

img 태그는 alt 속성이 있으면 aria-label을 무시한다.

<img src="..." alt="사용됨" aria-label="무시됨">
<img src="..." aria-label="사용됨">

 

다국어 지원

aria-label도 번역해야 한다는 걸 잊지 말자.

<!-- 한국어 -->
<button aria-label="메뉴 열기">
  <svg>...</svg>
</button>

<!-- 영어 -->
<button aria-label="Open menu">
  <svg>...</svg>
</button>

 

지원하지 않는 요소

<strong>, <em>, <code> 같은 요소들은 기본적으로 aria-label을 지원하지 않는다. role을 추가하면 사용할 수 있긴 하다.

 

다음 역할들도 aria-label을 지원하지 않는다: code, caption, deletion, emphasis, generic, insertion, mark, paragraph, presentation/none, strong, subscript, superscript, suggestion, term, time

 

자주 하는 실수

불필요한 중복

<!-- ❌ -->
<button aria-label="제출 버튼">제출</button>
<!-- 읽힘: "제출 버튼" -->

<!-- ✅ -->
<button>제출</button>
<!-- 읽힘: "제출, 버튼" -->

버튼은 이미 역할로 "버튼"이라고 알려주는데 또 말할 필요가 없다.

 

너무 긴 설명

aria-label은 짧고 명확해야 한다. 긴 설명이 필요하면 aria-describedby를 쓰는 게 낫다.

<!-- ❌ -->
<button aria-label="이 버튼을 클릭하면 현재 작성 중인 내용이 모두 삭제됩니다. 삭제된 내용은 복구할 수 없으니 주의하세요.">
  삭제
</button>

<!-- ✅ -->
<button aria-label="삭제" aria-describedby="delete-desc">
  삭제
</button>
<div id="delete-desc" class="sr-only">
  삭제된 내용은 복구할 수 없습니다.
</div>

 

테스트 방법

브라우저와 스크린 리더마다 동작이 조금씩 다를 수 있다. 실제로 테스트해보는 게 제일 확실하다.

  • Windows: NVDA (무료) 또는 JAWS
  • macOS: VoiceOver (내장)
  • 브라우저 확장: 스크린 리더 시뮬레이터

 

처음엔 복잡해 보이지만 핵심은 간단하다. 상호작용 요소는 대체, 콘텐츠 요소는 추가. 이것만 기억하면 대부분의 상황에서 제대로 쓸 수 있다.

'Frontend' 카테고리의 다른 글

Zustand로 전역 상태 관리하기  (0) 2025.11.18
웹 애플리케이션의 렌더링 방식과 Next.js  (0) 2025.11.08
타입스크립트 유틸리티 타입  (0) 2025.11.05
타입스크립트 타입 시스템: 계층과 호환성  (0) 2025.10.31
타입스크립트의 동작 원리  (0) 2025.10.27
'Frontend' 카테고리의 다른 글
  • Zustand로 전역 상태 관리하기
  • 웹 애플리케이션의 렌더링 방식과 Next.js
  • 타입스크립트 유틸리티 타입
  • 타입스크립트 타입 시스템: 계층과 호환성
고견
고견
개발 자국 남기기
  • 고견
    개발자국
    고견
  • 전체
    오늘
    어제
    • 분류 전체보기 (157) N
      • Frontend (29)
        • Next.js (16)
        • JavaScript (7)
      • CS (19) N
        • 자료구조 (9)
        • 알고리즘 (5)
        • 운영체제 (4) N
        • 네트워크 (1) N
      • TIL (93)
      • Dev Log (16)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    algorithm
    페이지 라우터
    앱 라우터
    타입 좁히기
    클래스
    Pages Router
    C
    바닐라 자바스크립트
    Spa
    Next.js
    emotion diary
    알고리즘
    generic
    ai 감성 일기장
    CS
    인터페이스
    함수 타입
    useState
    javascript
    제네릭
    트러블 슈팅
    memory
    cs50
    배열
    Trouble Shooting
    App Router
    typescript
    react
    자료구조
    문자열
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
고견
aria-label과 텍스트 콘텐츠
상단으로

티스토리툴바