사전 role
표준

role

gabury1고친 사람 github-actions[bot]

role 은 웹 페이지의 부품이 무엇인지를 화면을 못 보는 사용자에게 알려 줍니다. 글을 소리로 읽어 주는 프로그램이 이 값을 읽고 「버튼」「탭」 같은 말로 전합니다. <div> 처럼 뜻 없이 묶기만 하는 태그로 짠 부품에 특히 필요합니다. 권한 관리에서 쓰는 role 은 이름만 같은 다른 뜻입니다.

쉽고 빠른 이해

role 은 태그에 「이 부품은 무엇이다」를 적어 두는 속성입니다. <div> 로 짠 탭 하나에 role="tab" 을 붙이면 그 <div> 가 탭으로 알려집니다.

이게 없으면 화면에서 탭처럼 보이는 상자도 읽어 주는 프로그램에게는 글자 덩어리입니다. 사용자는 그걸 눌러 볼 수 있는지조차 모릅니다.

  1. 태그에 role="tab" 처럼 정해진 낱말 하나를 적습니다
  2. 브라우저가 그 낱말을 부품의 역할로 정합니다
  3. 읽어 주는 프로그램이 「설정, 탭」처럼 이름과 역할을 함께 읽습니다

대가는 알리기만 한다는 것입니다. 탭이라고 적어도 키보드로 옮겨 다니게 하는 코드는 직접 짜야 합니다. 태그가 원래 가진 역할도 덮어씁니다. 그래서 뜻이 맞는 태그가 이미 있으면 role 대신 그 태그를 씁니다.

상세

<div> 로 짠 탭 묶음 하나를 예로 삼아, 역할이 어디서 오는지부터 role 을 쓰는 때까지 차례로 봅니다.

데이터베이스나 클라우드에서 권한을 묶어 계정에 건네는 단위도 role 이라 부릅니다. 그 뜻은 롤이 다룹니다. 이 글은 웹 페이지 태그에 붙는 role 속성만 다룹니다.

부품의 역할

보조 기술은 장애가 있는 사용자가 컴퓨터를 쓰도록 돕는 소프트웨어와 기기입니다. 그중 스크린 리더는 화면의 글과 부품을 소리나 점자로 읽어 줍니다. 사용자는 키보드로 부품 사이를 옮겨 다니며 「저장, 버튼」 같은 안내를 듣습니다.

스크린 리더는 화면에 그려진 그림을 보지 않습니다. 브라우저가 따로 정리해 넘기는 부품 명단을 읽습니다. 이 명단이 접근성 트리입니다.

명단의 부품마다 역할이 하나씩 붙습니다. 역할은 그 부품이 무엇인지를 뜻합니다. 버튼인지, 링크인지, 제목인지가 역할입니다.

역할은 사용자에게 무엇을 할 수 있는지를 알려 줍니다. 「버튼」을 들으면 누를 수 있다는 것을 압니다. 「제목」을 들으면 새 단락이 시작된다는 것을 압니다. 역할이 없으면 사용자는 글자만 듣고 그 부품을 어떻게 다룰지 짐작해야 합니다.

태그가 스스로 가진 역할

웹 페이지는 HTML(HyperText Markup Language)로 씁니다. HTML 의 태그 대부분은 역할을 처음부터 갖고 있습니다. 브라우저는 페이지를 읽으면서 태그를 보고 역할을 정합니다.

이렇게 태그에서 저절로 따라오는 역할을 암묵적 역할이라고 합니다. 만든 사람이 아무것도 적지 않아도 붙는다는 뜻입니다.

태그 브라우저가 정하는 역할
<button> 버튼 (button)
<a href="…"> 링크 (link)
<h1> ~ <h6> 제목 (heading)
<ul> · <ol> 목록 (list)
<nav> 메뉴 구역 (navigation)
<input type="checkbox"> 체크박스 (checkbox)
<div> · <span> 없음

표의 마지막 줄이 문제의 출발점입니다. <div> 와 <span> 은 겉모양을 묶으려고 쓰는 상자 태그라 역할이 없습니다. 이 태그로 버튼을 짜면 화면에서는 버튼처럼 보여도 스크린 리더에게는 글자일 뿐입니다.

role 속성으로 역할 적기

role 은 ARIA(Accessible Rich Internet Applications)가 정한 속성입니다. ARIA 는 태그에 속성을 덧붙여 접근성 트리의 내용을 바꾸는 표준입니다.

role 속성은 그중에서도 역할을 적는 단 하나의 속성입니다. 이름과 상태를 적는 나머지 속성은 전부 aria- 로 시작합니다. 역할만 role 이라는 따로 된 이름을 씁니다.

아래 세 줄은 스타일을 입히면 화면에서 똑같은 탭 머리(누르는 탭 이름표 하나)로 보입니다. 오른쪽 주석은 브라우저가 정하는 역할입니다.

HTML
<button>설정</button>        <!-- 버튼 -->
<div>설정</div>              <!-- 없음 -->
<div role="tab">설정</div>   <!-- 탭 -->

둘째 줄은 역할이 없어 스크린 리더가 「설정」이라는 글자만 읽습니다. 셋째 줄은 role="tab" 이 역할을 채워 「설정, 탭」으로 읽힙니다. 화면의 모양과 동작은 셋째 줄에서도 하나도 바뀌지 않습니다.

원래 역할을 덮어쓰기

role 은 비어 있는 역할을 채우기만 하지 않습니다. 태그가 이미 가진 역할 위에 적으면 그 역할을 덮어씁니다. 브라우저는 role 에 적힌 값을 태그의 역할보다 앞세웁니다.

아래 두 줄의 오른쪽 주석도 역할입니다.

HTML
<h2>공지</h2>                <!-- 제목 -->
<h2 role="tab">공지</h2>     <!-- 탭 -->

둘째 줄은 화면에서 여전히 큰 제목 글씨입니다. 그런데 스크린 리더에게는 제목이 아니라 탭입니다. 스크린 리더 사용자는 페이지의 제목만 골라 건너다니기도 합니다. 그 목록에서 이 줄이 빠집니다.

그래서 태그의 원래 역할이 이미 맞으면 role 을 붙이지 않습니다. <button role="button"> 처럼 같은 값을 다시 적는 것도 쓸모가 없습니다.

적을 수 있는 값

role 의 값은 아무 낱말이나 될 수 없습니다. ARIA 가 정해 둔 역할 이름 가운데 하나를 적습니다. 브라우저가 모르는 낱말이면 role 이 없는 것으로 치고 태그의 원래 역할로 돌아갑니다.

HTML
<div role="buton">저장</div> <!-- 없음 -->

button 을 buton 으로 잘못 적은 줄입니다. 화면에서는 아무 차이가 없어 만든 사람이 알아채기 어렵습니다.

정해 둔 역할 이름은 하는 일에 따라 몇 갈래로 나뉩니다.

갈래 알리는 것 예
위젯 사용자가 만지는 부품 button · tab · checkbox · slider
문서 구조 글의 짜임 heading · list · img · table
랜드마크 페이지의 큰 구역 navigation · main · banner · search
라이브 리전 저절로 바뀌는 영역 alert · status · log
창 페이지 위에 뜨는 창 dialog · alertdialog

위젯 역할은 누르고 고르고 끄는 부품입니다. 이 갈래가 role 을 가장 자주 쓰는 갈래입니다. 탭처럼 HTML 에 맞는 태그가 없는 부품이 여기 많기 때문입니다.

랜드마크는 페이지를 큰 구역으로 나눈 표지입니다. 스크린 리더 사용자는 랜드마크 사이를 건너뛰어 본문이나 메뉴로 바로 갑니다. 눈으로 보는 사람이 화면을 훑어 본문을 찾는 일을 대신합니다.

라이브 리전은 내용이 바뀌면 스크린 리더가 알아서 읽어 주는 영역입니다. role="alert" 를 붙인 상자에 「저장에 실패했습니다」가 뜨면 사용자가 다른 부품에 있어도 그 말을 듣습니다.

역할이 데려오는 짝

역할 하나로 끝나지 않는 부품이 많습니다. 어떤 역할은 함께 적어야 하는 상태가 있습니다. 어떤 역할은 특정 역할 안에서만 뜻이 섭니다.

체크박스가 앞의 경우입니다. role="checkbox" 만 적으면 스크린 리더는 체크박스인 줄은 알아도 체크됐는지 모릅니다. 그래서 체크 상태를 알리는 aria-checked 를 반드시 함께 적습니다.

탭이 뒤의 경우입니다. 탭 머리는 탭 묶음 안에 있어야 합니다. 그리고 자기가 여닫는 내용 상자를 가리킵니다. 아래 그림은 세 역할이 맞물리는 모양입니다.

flowchart TD
    L["tablist · 탭 묶음"] --> T1["tab · 설정 · 선택됨"]
    L --> T2["tab · 알림"]
    T1 -->|aria-controls 로 가리킴| P1["tabpanel · 설정 내용"]
    T2 -->|aria-controls 로 가리킴| P2["tabpanel · 알림 내용"]

tablist 는 탭 머리들을 묶는 역할입니다. tab 은 누르는 탭 머리 하나입니다. tabpanel 은 그 탭을 누르면 보이는 내용 상자입니다. 그림을 태그로 옮기면 아래가 됩니다.

HTML
<div role="tablist">
  <div role="tab" aria-selected="true"
       aria-controls="p1">설정</div>
  <div role="tab" aria-selected="false"
       aria-controls="p2">알림</div>
</div>
<div role="tabpanel" id="p1">…</div>
<div role="tabpanel" id="p2">…</div>

aria-selected 는 지금 고른 탭이 어느 것인지 알립니다. 고른 탭에는 true, 나머지에는 false 를 적습니다.

aria-controls 는 탭 머리가 어느 내용 상자를 여닫는지 가리킵니다. 가리킬 때는 id 를 씁니다. id 는 문서 안에서 태그 하나에 붙이는 고유한 이름입니다.

이 짝이 맞으면 스크린 리더는 「설정, 탭, 선택됨」에 더해 묶음 안에서 몇 번째 탭인지까지 알려 줍니다. tab 이 tablist 밖에 홀로 있으면 묶음을 알 수 없어 순서가 안 나옵니다.

role 이 해 주지 않는 일

role 은 접근성 트리의 역할만 바꿉니다. 그 역할에 맞는 동작은 하나도 붙여 주지 않습니다. 버튼이라고 알려도 키보드로 눌리게 되지는 않습니다.

키보드 입력을 받을 차례가 된 부품을 포커스를 받았다고 합니다. <button> 과 <div role="button"> 을 견주면 차이가 드러납니다.

<button> <div role="button">
스크린 리더가 버튼으로 읽음 ✓ ✓
Tab 키로 포커스를 받음 ✓ ✗
Enter · 스페이스 키에 눌림 ✓ ✗
폼 안에서 제출을 일으킴 ✓ ✗

<div role="button"> 쪽이 <button> 과 같아지려면 할 일이 둘 붙습니다. tabindex 속성을 0 으로 적어 Tab 키로 포커스가 오게 합니다. 그리고 Enter 와 스페이스 키를 받는 코드를 자바스크립트로 짭니다.

이것이 role 의 대가입니다. 역할을 알린 순간 그 역할이 약속하는 조작을 만든 사람이 다 채워야 합니다. <button> 은 이 약속을 처음부터 지키고 있습니다.

역할이 약속하는 조작

역할은 이름만 알리지 않고 조작 방법까지 알립니다. 스크린 리더 사용자는 역할을 듣고 어느 키를 누를지 정합니다.

role="menu" 가 자주 틀리는 예입니다. 이 역할은 프로그램 위쪽의 「파일 · 편집」 같은 메뉴를 뜻합니다. 사용자는 이 역할을 들으면 화살표 키로 항목 사이를 옮겨 다닐 수 있다고 기대합니다.

웹사이트 위쪽의 링크 묶음에 role="menu" 를 붙이면 사용자는 화살표 키를 누릅니다. 그런데 링크 묶음에는 그 키를 받는 코드가 없어 아무 일도 안 일어납니다. 링크 묶음은 <nav> 안에 링크 목록을 두면 충분합니다.

틀린 role 은 role 이 없는 것보다 사용자를 더 헤매게 합니다. role 이 없으면 글자로라도 읽힙니다. 틀리면 사용자는 없는 조작을 믿고 키를 누르게 됩니다.

역할을 지우는 값

role="none" 은 태그의 역할을 지웁니다. 같은 뜻의 옛 이름으로 role="presentation" 도 씁니다. 안의 글은 남기고 그 태그가 무엇인지만 접근성 트리에서 뺍니다.

표를 칸 배치용으로만 쓴 페이지가 쓰는 곳입니다. <table> 은 역할이 표라서 스크린 리더가 「표, 3행 2열」처럼 읽고 칸 사이를 표처럼 오가게 합니다. 내용이 표가 아니면 이 안내가 사용자를 헷갈리게 합니다.

HTML
<table role="none">  <!-- 표 역할 지움 -->
  <tr><td>로고</td><td>검색</td></tr>
</table>

이 표는 화면에서는 두 칸으로 나란히 놓입니다. 스크린 리더는 「로고」「검색」 글자만 차례로 읽습니다.

쓰는 때와 안 쓰는 때

앞에서 본 것을 상황별로 표 하나에 모읍니다. 위에서부터 보고 맞는 줄에서 멈춥니다.

표에 처음 나오는 부품이 하나 있습니다. 콤보박스는 글을 치면서 목록에서 고르는 입력 칸입니다. 탭과 같이 HTML 에 통째로 맞는 태그가 없어 role 로 짭니다.

상황 쓰는 것
버튼 · 링크 · 체크박스처럼 맞는 태그가 있다 그 태그. role 을 안 붙인다
태그가 이미 맞는 역할을 가졌다 아무것도 안 붙인다
탭 · 콤보박스처럼 맞는 태그가 없다 role 과 짝 속성, 키보드 처리 코드
저절로 뜨는 오류 알림 role="alert"
칸 배치에만 쓴 표 role="none"

첫 줄이 나머지보다 앞섭니다. 뜻에 맞는 태그를 골라 쓰는 방식을 시맨틱 마크업이라 부릅니다. role 은 그 방식으로 풀리지 않을 때 꺼냅니다.

역할이 붙었는지 확인하기

role 은 화면에 안 보이니 눈으로 확인할 수 없습니다. 브라우저 개발자 도구의 접근성 패널을 열면 부품마다 정해진 역할이 보입니다. 암묵적 역할인지 role 로 적은 역할인지도 같이 나옵니다.

테스트 코드로도 확인합니다. Playwright 는 브라우저를 코드로 조종해 화면을 시험하는 도구입니다. 아래 한 줄은 역할이 탭이고 이름이 알림인 부품을 찾아 누릅니다.

Python
page.get_by_role("tab", name="알림").click()

role 이 빠졌거나 오타가 나면 이 줄이 부품을 못 찾아 실패합니다. 스크린 리더가 못 알아볼 탭을 테스트가 먼저 잡아 주는 셈입니다.

관련 항목

role 이 속하는 상위 표준과 분류

ARIA · 접근성 · 웹 접근성 · WCAG · W3C · WAI · HTML

role 과 함께 부품을 설명하는 ARIA 속성

aria-label · aria-labelledby · aria-describedby · aria-hidden · aria-selected · aria-checked · aria-expanded · aria-controls · aria-live

role 값이 바꾸는 접근성 트리의 정보

접근성 트리 · 암묵적 역할 · 접근 가능한 이름 · 이름 계산 · DOM

role 로 적는 역할의 갈래

위젯 역할 · 문서 구조 역할 · 랜드마크 · 라이브 리전 · 추상 역할

role 을 붙여 짜는 부품

탭 · 콤보박스 · 트리 메뉴 · 모달 대화상자 · 체크박스 · 메뉴 버튼

role 값을 읽어 전하는 보조 기술

보조 기술 · 스크린 리더 · 점자 디스플레이 · 음성 제어

role 보다 먼저 쓰는 HTML 수단

시맨틱 마크업 · button 요소 · nav 요소 · 키보드 접근성 · tabindex · 포커스

role 이 붙었는지 살피는 도구

개발자 도구 · Playwright · 로케이터 · Testing Library · 자동 검사

role 과 이름만 같은 권한 관리 개념

롤 · 역할 기반 접근 제어 · AWS IAM · 권한 · 최소 권한

다른 이름: role 속성 · ARIA 역할 · ARIA role