아래 내용은 MDN 접근성 가이드 문서로 게시된 글입니다. 접근성에 대해 알아야 할 것중에서 WAI-ARIA를 가볍게 살펴보고 어떤 식으로 동작하고 기존 기능을 개선하는지 살펴보기 위해 번역했습니다. 아마도 이 글을 보는 것보다 이 글을 작성한 시점보다 좀 더 나아진 기계번역의 힘을 빌리는 것이 좀 더 좋은 방법이라 생각됩니다.
원문: https://developer.mozilla.org/en-US/docs/Learn/Accessibility/WAI-ARIA_basics
* 원문에 포함된 일부 링크는 포함하지 않았습니다. 원문은 실제 코드를 받아서 로컬 환경에서 수정해보는 과정을 진행하는데 여기에서는 그냥 가볍게 살펴보는 정도로만 다시 구성했습니다.
의미가 없는 HTML과 동적으로 업데이트되는 자바스크립트 콘텐츠가 포함된 복잡한 UI 컨트롤은 접근성에 좋지 않은 영향을 미칠 수 있습니다. WAI-ARIA는 브라우저와 보조 기술이 정보를 인식하고 사용자에게 무슨 일이 일어나고 있는지 알려주는 데 사용할 수 있는 추가 시맨틱 정보를 추가해 이런 문제를 해결하는 데 도움이 되는 기술입니다. 여기에서는 접근성을 개선하기 위해 기본적인 수준에서 이를 활용하는 방법을 보여드리겠습니다.
목표
필요에 따라 접근성을 향상시키는 데 유용한 추가 시맨틱 정보를 제공하는 데 WAI-ARIA를 어떻게 사용할 수 있는지 익힙니다.
WAI-ARIA란 무엇인가요?
먼저 WAI-ARIA가 무엇인지 살펴보고 이를 통해 무엇을 할 수 있는지 알아봅시다.
완전히 새로운 문제
웹 앱이 복잡해지고 동적으로 변경할 수 있게 되면서 새로운 접근성 기능과 문제가 나타나기 시작했습니다.
예를 들어 HTML은 일반적인 페이지 기능을 정의하기 위해 여러 시맨틱 요소(<nav>, <footer> 등)을 도입했습니다. 이런 기능이 나오기 전에는 개발자가 ID 또는 class 속성을 설정한 <div> 태그(<div class='nav'> 형태)를 사용했지만 기본 제공되는 프로그래밍으로는 특정 영역으로 바로 건너뛰는 기본적인 탐색 기능을 구현하기 쉽지 않아 문제가 있었습니다.
초기에 찾은 해결책은 페이지 상단에 숨겨진 링크를 하나 이상 추가해 특정 콘텐츠 또는 다른 링크로 바로 연결하는 것이었습니다. 예를 들면 아래와 같은 코드입니다.
<a href="#hidden" class="hidden">Skip to navigation</a>
하지만 이런 방식은 여전히 정확하지 않으며 스크린 리더가 페이지 상단부터 읽는 경우에만 유효합니다.
또 다른 예로 날짜를 선택하는 날짜 선택기나 값을 선택하는 슬라이더 같은 복잡한 컨트롤이 앱에 등장하기 시작했습니다. HTML은 이런 컨트롤을 렌더링 하기 위해 특수한 input type을 제공하고 있습니다.
<input type="date" /> <input type="range" />
이런 기능은 초기에는 잘 동작하지 않았고 스타일을 적용하기도 어려웠습니다. 지금은 좀 나아지긴 했지만 여전히 디자이너나 개발자는 다른 해결책을 찾고 있습니다. 때문에 일부 개발자는 기본 기능 대신 중첩된 <div>로 컨트롤을 생성하고 CSS를 사용해 스타일을 적용한 후 자바스크립트로 이를 제어할 수 있는 별도의 라이브러리에 의존합니다.
이런 라이브러리를 사용하는 경우 시각적으로는 작동하는 것처럼 보이지만 스크린 리더는 그 내용을 전혀 이해할 수 없으며 사용자는 이것이 어떤 것을 나타내는지에 대한 설명이 전혀 없이 일련의 요소들이 뒤섞여 있다는 메시지만 접하게 됩니다.
WAI-ARIA의 등장
WAI-ARIA(웹 접근성 이니셔티브 - 접근 가능한 리치 인터넷 애플리케이션)는 W3C에서 작성한 사양으로 요소에 적용해 추가적인 의미를 제공하고 접근성이 부족한 부분을 개선할 수 있는 일련의 추가 HTML 속성을 정의합니다. 이 사양은 세 가지 주요 기능이 정의되어 있습니다.
- 역할 - 요소 그 자체를 정의하거나 요소의 기능을 정의합니다. 대부분은 랜드마크로서 역할을 합니다. role="navigation" (<nav>) 또는 role="complementary" (<aside>) 같은 경우는 구조적 요소의 시맨틱 값과 중복되는 역할을 합니다. 그리고 role="banner", role="search", role="tablist", role="tabpanel"처럼 UI에서 흔히 볼 수 있는 구조를 정의하기도 합니다.
- 속성 - 요소의 속성을 정의하며 요소에 추가적인 의미나 시맨틱 값을 부여하는 데 사용할 수 있습니다. 예를 들어 aria-required="true"라는 값은 입력폼이 유효하려면 입력란을 채워야 한다고 지정하는 것이고 aria-labelledby="label"이라고 설정하면 해당 요소에 ID를 설정하고 페이지 내 다른 모든 요소에서 label 값을 참조할 수 있습니다. 이렇게 하면 여러 요소의 ID를 동시에 참조할 수 있는데 <label for="input">을 사용하면 여러 요소를 참조하는 것은 불가능합니다. 예를 들어 aria-labelledby 속성을 사용해 <div>에 포함된 설명을 테이블 내 각 셀 요소의 label로 사용하거나 image 대체 텍스트처럼 사용할 수 있습니다. 즉 페이지 내 이미 정의된 정보를 alt 속성에서 반복해서 작성하지 않고 image의 alt 속성값으로 사용할 수 있습니다.
- 상태 - 요소의 현재 상태를 정의하는 특수 속성입니다. 예를 들어 aria-disabled="true"라는 값은 스크린 리더에 현재 양식 입력 상태가 비활성화된 상태라는 것을 알려줍니다. 상태는 일반적으로 자바스크립트를 통해 프로그래밍 방식으로 변경할 수 있는 반면 속성은 앱의 수명 주기 동안에는 변경되지 않는다는 점에서 속성과 다릅니다.
WAI-ARIA 속성에 대해 알아야 할 또 하나의 중요한 점은 브라우저의 접근성 API(스크린 리더가 정보를 가져오는)에 의해 노출되는 정보를 제외하면 웹 페이지 자체에는 영향을 주지 않는다는 것입니다. 이 속성은 CSS로 요소를 선택하는 데 유용할 수 있지만 웹 페이지 구조, DOM 등에는 영향을 주지 않습니다.
WAI-ARIA가 지원되는 환경은 어떤 것인가요?
이 질문에 답하기는 쉽지 않습니다. WAI-ARIA의 어떤 기능이 어디에서 어떤 식으로 지원되는지 명시적으로 정리된 리소스를 찾기가 어렵기 때문입니다.
- WAI-ARIA 사양에는 많은 기능이 포함되어 있습니다.
- 실행 시 고려해야 할 운영체제, 브라우저, 스크린 리더의 조합이 너무 많습니다.
두 번째 상황이 중요합니다. 스크린 리더를 사용하려면 운영체제에서 스크린 리더가 작업을 수행하는 데 필요한 정보를 노출해 줄 수 있는 접근성 API가 있는 브라우저를 실행해야 합니다. 대부분 운영 체제에서는 스크린 리더가 적절하게 동작할 수 있는 브라우저를 찾을 수 있습니다.
그러고 나서 해당 브라우저가 ARIA 기능을 지원하고 API를 통해 해당 기능을 노출하는지 여부, 스크린 리더가 해당 정보를 인식하여 사용자에게 유용한 방식으로 표시하는지 여부도 고려해야 합니다.
- 브라우저 지원은 큰 문제가 없습니다.
- ARIA 기능에 대한 스크린 리더 지원은 아직 이 수준에는 미치지 못하지만 가장 많이 사용하는 스크린 리더는 이 수준에 도달하고 있습니다.
이 글에서 모든 WAI-ARIA 기능과 정확한 지원 여부까지는 다루지 않을 겁니다. 대신 사용자가 알아야 할 가장 중요한 WAI-ARIA 기능을 다루며 따로 언급이 없으면 일반적인 환경에서 해당 기능이 잘 지원되는 것으로 간주해도 괜찮습니다. 예외적인 경우는 따로 언급하도록 하겠습니다.
일부 자바스크립트 라이브러리는 복잡한 양식 컨트롤과 같은 UI 기능 생성 시 ARIA 속성을 추가해 해당 기능의 접근성을 개선하는 형태로 WAI-ARIA를 지원합니다. 빠른 UI 개발을 위해 자바스크립트 솔루션을 찾고 있다면 해당 UI 위젯의 접근성을 중요한 요소로 고려해야 합니다. jQuery UI나 ExtJS, Dojo/Dijit에서 어떤 식으로 접근성을 지원하고 있는지 살펴보세요.
https://jqueryui.com/about/#deep-accessibility-support
https://www.sencha.com/products/extjs/
https://dojotoolkit.org/reference-guide/1.10/dijit/a11y/statement.html
WAI-ARIA는 언제 사용해야 하나요?
앞에서 WAI-ARIA가 등장하게 된 몇 가지 배경을 이야기했습니다. 기본적으로 WAI-ARIA는 4가지 영역에서 주로 사용합니다.
- 이정표/랜드마크: ARIA의 role 속성값은 HTML 요소(예를 들면 <nav>)와 같은 역할을 하거나 HTML에서 제공하지 못하는 다양한 기능 영역(예를 들면 검색, 탭, 목록 등)에 대한 이정표를 제공하는 랜드마크 역할을 할 수 있습니다.
- 동적 콘텐츠 업데이트: 스크린 리더는 지속적으로 변경되는 콘텐츠에 대한 정보를 처리하는 데 어려움을 겪고 있는데 ARIA를 사용하면 aria-live 속성을 통해 콘텐츠 영역이 업데이트될 때 XMLHttpRequest 또는 DOM API를 통해 스크린 리더에게 필요한 정보만 전달할 수 있습니다.
- 키보드 접근성 향상: HTML 요소만 사용하더라도 기본적인 키보드 접근성은 지원하지만 자바스크립트에서 특정 동작을 제어하는 경우 키보드 접근성과 스크린 리더에서 처리할 수 있는 정보에 영향을 미칩니다. 이런 상황에서 WAI-ARIA는 tabindex를 사용해 다른 요소가 포커스를 받을 수 있도록 조정할 수 있습니다.
- 시맨틱 정보가 없는 컨트롤의 접근성: 복잡한 UI를 구현하기 위해 일련의 중첩된 <div>와 CSS, 자바스크립트를 함께 사용하거나 자바스크립트로 기본 컨트롤 기능을 변경하는 경우 접근성이 저하될 수 있습니다. 스크린 리더 사용자는 시맨틱 정보가 없거나 다른 단서가 없으면 해당 기능이 무엇을 하는지 파악하기 어렵습니다. 이런 상황에서 ARIA는 role 속성값을 button, listbox, tablist 등으로 설정하고 aria-required 또는 aria-posinset 같은 속성을 조합해 기능에 대한 추가적인 단서를 제공하는데 도움을 줄 수 있습니다.
한 가지 기억해야 할 점은 꼭 필요한 경우에만 WAI-ARIA를 사용해야 한다는 것입니다. 이상적으로는 네이티브 HTML 기능을 사용해 사용자에게 무슨 일이 일어나고 있는지 알려주는 데 필요한 시맨틱 정보를 스크린 리더에게 제공해야 합니다. HTML만으로는 코드를 제어하기 어렵거나 구현하기 복잡한 경우처럼 불가피한 경우가 있습니다. 이런 경우 WAI-ARIA는 접근성을 향상시키는 유용한 도구가 될 수 있습니다.
다시 강조하지만 꼭 필요한 경우에만 사용하세요!
또한 비장애인, 스크린 리더 사용자, 탐색 시 키보드를 주로 사용하는 사용자 등 다양한 실제 사용자와 함께 테스트를 진행하세요. 이들은 사이트가 얼마나 잘 작동하는지 여러분보다 더 잘 파악할 수 있을 겁니다.
WAI-ARIA 직접 다루어보기
다음 섹션에서는 실제 예제를 통해 네 가지 영역을 자세히 살펴보겠습니다. 계속 진행하기 전에 스크린 리더 테스트를 위한 설정을 준비해야 몇 가지 예제를 직접 테스트해 볼 수 있습니다.
자세한 내용은 스크린 리더 테스트 항목을 참조하세요.
이정표/랜드마크
WAI-ARIA는 브라우저에 role 속성을 추가해 사이트의 각 요소에 필요한 추가적인 시맨틱 정보를 추가할 수 있습니다. 이 기능이 유용한 첫 번째 주요 영역은 사용자가 일반적인 페이지 요소를 찾을 수 있도록 스크린 리더에 정보를 제공하는 것입니다. 예시를 살펴보겠습니다. 웹사이트에 role 정보가 없는 구조는 다음과 같습니다. 링크도 같이 참고하세요.
https://mdn.github.io/learning-area/accessibility/aria/website-no-roles/
<header>
<h1>…</h1>
<nav>
<ul>
…
</ul>
<form>
<!-- search form -->
</form>
</nav>
</header>
<main>
<article>…</article>
<aside>…</aside>
</main>
<footer>…</footer>
최신 브라우저에서 보이스오버로 이 예제를 테스트해 보면 몇 가지 유용한 정보를 얻을 수 있습니다. 예를 들어 다음과 같은 정보를 읽어줍니다.
- On the <header> element — "banner, 2 items" (it contains a heading and the <nav>).
- On the <nav> element — "navigation 2 items" (it contains a list and a form).
- On the <main> element — "main 2 items" (it contains an article and an aside).
- On the <aside> element — "complementary 2 items" (it contains a heading and a list).
- On the search form input — "Search query, insertion at beginning of text".
- On the <footer> element — "footer 1 item".
보이스오버의 랜드마크 메뉴(보이스오버 키 + U를 사용해 접근한 다음 커서 키를 사용해 메뉴 선택 항목을 순환할 수 있습니다)로 이동하면 대부분의 요소가 깔끔하게 나열되어 있어 빠르게 접근할 수 있음을 알 수 있습니다.
* 윈도우 11에서는 내레이터를 활성화할 수 있습니다. 윈도우 키 + Ctrl + Enter 키로 활성화하고 Insert + F5 키를 입력하면 '랜드마크 검색' 화면으로 이동합니다.
하지만 좀 더 잘 만들 수 있습니다. 검색 양식은 사용자가 찾고 싶어 하는 매우 중요한 랜드마크이지만, 랜드마크 메뉴에 나열되지 않거나 검색 입력(<input type="search">)으로 호출되는 실제 입력부 외에는 주목할만한 랜드마크처럼 취급되지 않습니다.
ARIA의 몇 가지 기능을 사용해 이 문제를 개선해 보겠습니다. 먼저 HTML 구조에 몇 가지 role 속성을 추가합니다. 웹사이트에 role 정보를 추가한 구조는 다음과 같습니다. 링크도 같이 참고하세요.
https://mdn.github.io/learning-area/accessibility/aria/website-aria-roles/
<header>
<h1>…</h1>
<nav role="navigation">
<ul>
…
</ul>
<form role="search">
<!-- search form -->
</form>
</nav>
</header>
<main>
<article role="article">…</article>
<aside role="complementary">…</aside>
</main>
<footer>…</footer>
이 예제에서는 <input> 요소에 aria-label 속성을 추가해 <label> 요소가 없어도 스크린 리더에서 읽을 수 있는 설명을 제공합니다. 검색 양식은 매우 일반적이며 쉽게 인식할 수 있는 기능이라 시각적인 라벨을 추가하면 페이지 디자인이 손상될 수 있습니다. 이럴 때 보이지 않는 정보를 추가하면 유용하게 사용할 수 있습니다.
<input
type="search"
name="q"
placeholder="Search query"
aria-label="Search through site content" />
이제 보이스오버를 사용해 예제를 살펴보면 몇 가지 개선 사항을 확인할 수 있습니다.
- 검색 양식이 페이지를 탐색할 때와 랜드마크 메뉴에서 모두 별도의 항목으로 처리됩니다.
- 양식 입력 영역에 포커스가 이동하면 aria-label 속성에 포함된 라벨 텍스트를 읽어줍니다.
* 내레이터에서 랜드마크 검색 결과는 아래와 같습니다.
IE8과 같은 구형 브라우저 사용자도 사이트에 접근할 가능성이 높으므로 이를 위해 ARIA role을 추가하는 것이 좋습니다(이건 좀 예전에 작성된 글이라). 그리고 이런저런 이유로 <div>만 사용해 사이트를 구축했다면 반드시 ARIA role을 포함해서 필요한 시맨틱 정보를 제공해야 합니다.
검색 양식의 개선된 시맨틱 정보는 ARIA가 HTML에서 사용할 수 있는 시맨틱 정보의 제약을 넘어설 수 있다는 것을 보여줍니다. 구체적인 내용은 시맨틱 정보를 가지지 못하는 컨트롤에 대한 접근성 섹션에서 ARIA 속성과 관련 기능을 자세히 살펴볼 겁니다. 하지만 여기에서는 ARIA가 동적 콘텐츠 업데이트 시 어떻게 도움을 줄 수 있는지 살펴보겠습니다.
동적 콘텐츠 업데이트
텍스트 콘텐츠부터 이미지에 첨부된 대체 텍스트까지 스크린 리더를 사용해 DOM에 로드된 콘텐츠에 쉽게 접근할 수 있습니다. 따라서 텍스트 콘텐츠가 대부분인 정적 웹사이트는 시각 장애자도 쉽게 정보를 확인할 수 있습니다.
문제는 최신 웹 앱에는 정적 텍스트뿐 아니라 동적으로 업데이트되는 콘텐츠, 즉 전체 페이지를 다시 로드하지 않고 업데이트되는 콘텐츠(XMLHttpRequest, Fetch 또는 DOM API와 같은 메커니즘을 통해 업데이트되는 콘텐츠)가 포함된 경우가 많다는 점입니다. 이를 라이브 영역이라고도 합니다.
간단한 예시를 살펴보겠습니다. 이 예시에는 간단한 임의의 명언을 표시해 주는 상자가 있습니다. 링크도 같이 참고하세요.
https://mdn.github.io/learning-area/accessibility/aria/aria-no-live.html
<section>
<h1>Random quote</h1>
<blockquote>
<p></p>
</blockquote>
</section>
자바스크립트에서는 일련의 무작위 명언과 작성자 정보가 담긴 JSON 파일을 XMLHttpRequest를 통해 로드합니다. 이 작업이 완료되면 10초마다 새로운 무작위 명언을 상자 안에 로드하는 setInterval 루프가 시작됩니다.
const intervalID = setInterval(showQuote, 10000);
기능적으로는 정상적으로 동작하지만 접근성 측면에서는 좋지 않습니다. 콘텐츠 업데이트가 스크린 리더에서 감지되지 않아서 사용자는 무슨 일이 일어나는지 알 수 없습니다. 이건 매우 사소한 예시이지만 채팅방, 전략 게임 UI, 실시간으로 업데이트되는 쇼핑몰의 장바구니 정보와 같이 지속적으로 업데이트되는 콘텐츠가 많은 복잡한 UI를 만든다고 상상해 보세요. 사용자에게 업데이트된 정보를 알려주는 방법이 없다면 앱을 효과적으로 사용할 수 없을 것입니다.
다행히 WAI-ARIA는 이런 정보를 업데이트해 주는 유용한 메커니즘인 aria-live 속성을 제공합니다. 이 속성을 요소에 적용하면 스크린 리더가 업데이트된 콘텐츠를 읽어줍니다. 콘텐츠가 얼마나 빠르게 읽어줄지는 속성값에 따라 달라집니다.
- off: default 값입니다. 업데이트 정보를 제공하지 않습니다.
- polite: 사용자가 특정 작업을 하지 않을 때만 업데이트 정보를 제공합니다.
- assertive: 업데이트가 발생하면 바로 사용자에게 업데이트 정보를 제공합니다.
<section> 여는 태그를 아래와 같이 수정해 줍니다.
<section aria-live="assertive">…</section>
이렇게 하면 스크린 리더에서 콘텐츠 업데이트 시 정보를 읽을 수 있습니다.
file:// URL 형태로 XMLHttpRequest를 호출하거나 더블 클릭 등의 사용자 동작으로 브라우저에서 직접 파일을 로드하는 경우에는 보안 예외가 발생합니다. 이를 우회하려면 파일을 GitHub와 같은 웹 서버나 파이썬의 SimpleHTTPServer와 같은 로컬 웹 서버에 업로드해야 합니다.
여기서 한 가지 더 고려해야 할 사항이 있는데, 업데이트되는 텍스트의 일부만 읽어주는 것입니다. 사용자가 내용을 인지할 수 있게 제목도 같이 읽어주는 것이 좋습니다. 이를 위해 섹션에 aria-atomic 속성을 추가하면 됩니다. 다음과 같이 <section> 여는 태그를 수정해 줍니다.
<section aria-live="assertive" aria-atomic="true">…</section>
aria-atomic 속성값을 true로 설정하면 스크린 리더가 업데이트된 내용의 일부가 아니라 전체 요소 콘텐츠를 하나의 단위로 처리해서 읽어주도록 지시합니다.
완성된 예제는 링크를 같이 참고하세요.
https://mdn.github.io/learning-area/accessibility/aria/aria-live.html
aria-relevant 속성은 라이브 영역이 업데이트될 때 읽어주는 내용을 제어하는 데에도 매우 유용합니다. 예를 들어 추가 또는 삭제된 콘텐츠만 읽도록 설정할 수 있습니다.
키보드 접근성 향상하기
앞에서 일부 언급한 것처럼 접근성과 관련해서 HTML의 주요 강점 중 하나는 버튼, 폼 컨트롤, 링크 같은 기능에 기본적인 키보드 접근성 기능을 지원한다는 점입니다. 일반적으로 tab 키를 사용해 컨트롤 사이를 이동하고 Enter/Return 키를 사용해 컨트롤을 선택하거나 활성화하며 필요에 따라 다른 컨트롤을 사용(예를 들면 위쪽, 아래쪽 커서를 사용해 <select> 상자의 옵션을 변경하는)할 수 있습니다.
하지만 때로 의미가 없는 요소를 버튼(또는 다른 유형의 컨트롤)처럼 사용하거나 포커스를 받을 수 있는 컨트롤을 원래 목적과 다르게 사용하는 코드를 작성해야 할 때가 있습니다. 상속받는 잘못된 코드를 수정하거나 이를 가지고 복잡한 위젯을 만들어야 할 수도 있습니다.
포커스를 받을 수 없는 대상을 포커스를 받을 수 있게 코드를 작성하기 위해 WAI-ARIA에서는 tabindex 속성에 몇 가지 설정값을 지정해 기능을 확장합니다.
- tabindex="0" - 이 값은 포커스를 tab 키 입력으로 포커스를 이동할 수 없는 요소를 tab 키 입력으로 이동하게 합니다. 가장 유용하게 사용하는 tabindex 속성값입니다.
- tabindex="1" - 일반적으로 tab 키 입력으로 포커스를 이동할 수 없는 요소를 자바스크립트 또는 링크의 대상으로 설정하는 프로그래밍 방식으로 포커스를 받을 수 있게 허용합니다.
HTML 접근성 문서에서 이에 대해 더 자세히 논의하고 일반적인 구현 방식을 설명합니다. 키보드 접근성 다시 구축하기 문서를 참고하세요.
시맨틱 정보가 없는 컨트롤에 대한 접근성
이전 섹션에 이어서 복잡한 UI 기능을 만들기 위해 일련의 중첩된 <div>를 CSS, 자바스크립트와 함께 사용하거나 네이티브 컨트롤이 자바스크립트를 통해 기능이 크게 확장되거나 변경되는 경우 키보드 접근성이 저하될 수 있으며 시맨틱 정보나 기타 단서가 없는 경우 스크린 리더 사용자는 해당 기능이 무엇을 하는지 파악하기 어려울 수 있습니다. 이럴 때 ARIA는 시맨틱 정보를 보완하는데 도움을 줄 수 있습니다.
양식의 유효성 검사와 오류 알림
이전에 CSS, 자바스크립트 접근성 문서에서 살펴보았던 예제를 다시 살펴보겠습니다. 해당 섹션에 마지막 부분에서 양식을 제출하려고 할 때 유효성 검사 오류를 표시하는 오류 메시지 상자에 일부 ARIA 속성을 포함했었습니다.
<div class="errors" role="alert" aria-relevant="all">
<ul></ul>
</div>
- role="alert"은 해당 요소를 자동으로 라이브 영역으로 전환해 변경 사항을 읽어주고 경고 메시지(시간, 상황적으로 민감한 정보)라는 시맨틱 정보를 식별하게 합니다. 그리고 사용자에게 경고를 전달하는데 더 나은 접근성 방식을 제안합니다(alert 함수를 직접 호출해 실행되는 모달 대화 상자는 여러 가지 접근성 문제가 있습니다. WebAIM의 팝업창을 참고하세요.
- aria-relevant 속성값이 "all"이면 오류 목록이 변경될 때(즉 오류가 추가, 제거될 때) 스크린 리더가 오류 목록의 내용을 읽도록 지시합니다. 이는 사용자가 목록에서 추가되거나 제거된 오류뿐 아니라 어떤 오류가 남아있는지 알고 싶어 하기 때문에 유용합니다. https://webaim.org/techniques/javascript/other#popups
ARIA 사용법을 좀 더 발전시키면 더 많은 유효성 검사에 활용할 수 있습니다. 예를 들어 처음부터 필드가 필수 항목인지 여부와 연령 범위를 표시하면 어떨까요?
<form> 태그 위에 아래와 같은 코드를 추가합니다. 그리고 <label> 태그로 지정한 값에 "*" 표시를 추가해 줍니다. 이렇게 하면 화면을 볼 수 있는 사용자에게 필수 항목임을 나타낼 수 있습니다.
<p>Fields marked with an asterisk (*) are required.</p>
하지만 시각 장애인은 이런 표시만으로는 스크린 리더에서 충분한 정보를 얻을 수 없습니다. 다행히 WAI-ARIA는 aria-required 속성을 제공해 스크린 리더가 사용자에게 양식 입력란을 채워야 한다는 힌트를 제공합니다.
<input type="text" name="name" id="name" aria-required="true" />
<input type="number" name="age" id="age" aria-required="true" />
코드를 수정하고 스크린 리더에서 확인해 보면 "Enter your name star, required, edit text"와 같이 읽어주는 것을 확인할 수 있습니다.
스크린 리더 사용자와 시각 장애인에게 연령 값에 대한 정보도 제공해 주면 유용할 수 있습니다. 일반적으로는 양식 필드 안에 툴팁이나 플레이스홀더 형태로 표시됩니다. WAI-ARIA에는 최솟값과 최댓값을 지정할 수 있는 aria-valuemin, aria-valuemax 속성이 포함되어 있으며 스크린 리더에서는 input 태그의 min, max 속성도 지원합니다. 또 다른 기능은 placeholder 속성입니다. 값을 입력하지 않았을 때 입력 필드에 표시되고 일부 스크린 리더에서는 이를 읽어줍니다. 숫자 입력 항목은 아래와 같이 수정합니다.
<label for="age">Your age:</label>
<input
type="number"
name="age"
id="age"
placeholder="Enter 1 to 150"
required
aria-required="true" />
항상 모든 입력에 <label>을 포함하세요. 일부 스크린 리더는 placeholder 텍스트를 읽어주지만 그렇지 않은 스크린 리더도 있습니다. 양식 컨트롤에 접근 가능한 이름을 제공하는 대신 사용할 수 있는 대체 방법은 aria-label과 aria-labelledby 속성이 있습니다. 하지만 for 속성이 있는 <label> 요소는 마우스 사용자를 포함한 모든 사용자에게 사용성을 제공하므로 선호하는 방법입니다.
최종 수정된 양식은 링크를 참고하세요.
https://mdn.github.io/learning-area/accessibility/aria/form-validation-updated.html
WAI-ARIA는 고전적인 <label> 요소를 확장해 몇 가지 향상된 양식 라벨링 기법을 지원합니다. 시각 장애인에게 라벨을 표시하지 않으려는 경우 aria-label 속성을 사용하여 라벨 정보를 제공하는 방법에 대해서는 앞에서 설명했습니다(이정표/랜드마트 항목을 참고하세요). <label> 아닌 요소를 라벨로 지정하거나 여러 양식 입력에 같은 라벨을 지정하려는 경우에는 aria-labelledby, 양식 입력에 다른 정보를 연결해 함께 읽도록 하는 경우에는 aria-describedby와 같은 다른 속성을 사용하는 라벨링 기법도 있습니다. 자세한 내용은 WebAIM의 고급 양식 라벨링 기법 문서를 참고하세요.
https://webaim.org/techniques/forms/advanced
양식 요소의 상태를 표시하는 데 유용한 다른 많은 속성과 상태도 있습니다. 예를 들어 aria-disabled="true"는 양식 필드가 비활성화되었음을 나타내는 데 사용할 수 있습니다. 많은 브라우저는 비활성화된 양식 필드를 건너뛰기 때문에 스크린 리더에서 읽지 않습니다. 하지만 일부 환경에서는 비활성화된 요소가 인식되어 스크린 리더에서 읽기를 시도하기 때문에 이런 속성을 사용해 비활성화된 양식 컨트롤이 실제 비활성화된 상태임을 스크린 리더에게 알려주는 것이 좋습니다.
비활성화 상태가 변경될 가능성이 있는 경우 변경되는 시기와 결과를 표시하는 것도 좋은 방법입니다. 예를 들어 form-validation-checkbox-disabled.html 데모에서는 체크박스를 선택하면 다른 양식 입력이 활성화되어 추가 정보를 입력할 수 있습니다. 이를 위해 숨겨진 라이브 영역을 설정했습니다.
<p class="hidden-alert" aria-live="assertive"></p>
절대 좌표를 사용해 화면에서 보이지 않게 설정했습니다. 이 옵션을 선택 또는 선택 취소하면 숨겨진 라이브 영역 내부의 텍스트를 업데이트해 스크린 리더 사용자에게 체크박스 선택 시 어떤 결과가 나타나는지 알려주며 aria-disabled 상태와 일부 시각적 상태도 업데이트합니다.
function toggleMusician(bool) {
const instruItem = formItems[formItems.length - 1];
if (bool) {
instruItem.input.disabled = false;
instruItem.label.style.color = "#000";
instruItem.input.setAttribute("aria-disabled", "false");
hiddenAlert.textContent =
"Instruments played field now enabled; use it to tell us what you play.";
} else {
instruItem.input.disabled = true;
instruItem.label.style.color = "#999";
instruItem.input.setAttribute("aria-disabled", "true");
instruItem.input.removeAttribute("aria-label");
hiddenAlert.textContent = "Instruments played field now disabled.";
}
}
시맨틱 정보가 없는 버튼을 버튼처럼 설명하기
앞에서 이미 몇 차례 버튼, 링크, 양식 요소의 기본 접근성(그리고 다른 요소를 조합해 만들 때 접근성 문제)에 대해 언급했습니다(HTML 접근성에서 UI 컨트롤, 키보드 접근성 강화하기 문서를 참고하세요). 기본적으로는 tabindex 속성과 약간의 자바스크립트를 사용하면 대부분의 경우 큰 문제없이 키보드 접근성을 다시 추가할 수 있습니다.
https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML#ui_controls
https://developer.mozilla.org/en-US/docs/Learn/Accessibility/WAI-ARIA_basics#enhancing_keyboard_accessibility
하지만 스크린 리더 사용 시에는 어떨까요? 스크린 리더는 해당 요소를 여전히 버튼으로 인식하지 못합니다. 스크린 리더에서 이를 테스트해 보면 "Click me! group"이라고 처리되는데 이는 사용자에게 혼란을 줄 수 있습니다.
WAI-ARIA role을 사용하면 이 문제를 해결할 수 있습니다. 예를 들어 아래와 같이 각 버튼을 나타내는 <div>에 role="button"으로 설정하는 코드를 추가합니다.
<div data-message="This is from the first button" tabindex="0" role="button">
Click me!
</div>
이제 스크린 리더를 사용해 접근해 보면 "Click me! button"으로 읽어줍니다. 이렇게 하면 훨씬 낫기는 하지만 여러분은 사용자가 버튼에 기대하는 기능 예를 들면 enter 또는 click 이벤트 처리 같은 기본 버튼의 기능을 직접 추가해주어야 합니다. button role 관련 문서를 참고하세요.
https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role
가능한 한 올바른 요소를 사용하는 것이 항상 더 좋다는 것을 잊지 마세요. 버튼을 만들고 싶고 <button> 요소를 사용하는데 문제가 없다면 <button> 요소를 사용하세요.
복잡한 위젯에 대한 정보 안내하기
콤보박스, 슬라이더, 탭 패널, 트리 등은 표준 HTML에서 지원하지 않지만 일반적으로 사용되는 UI 기능입니다. 이런 시맨틱 정보를 가지고 있지 않은 복잡한 요소 구조를 식별할 때는 여러 가지 role을 같이 사용합니다. Deque 대학(*Deque University는 접근성 전문 기업 Deque Systems에서 운영하는 온라인 교육, 리소스 사이트입니다)에서 사용한 코드 라이브러리에서 몇 가지 유용한 예제를 통해 이런 컨트롤을 어떻게 접근할 수 있는지에 대한 아이디어를 얻을 수 있습니다.
https://dequeuniversity.com/library/
저희가 직접 만든 예제를 살펴보겠습니다. 탭 상자 예제에서 확인할 수 있는 간단한 절대 위치 탭 인터페이스를 확인해 보죠.
https://github.com/mdn/learning-area/blob/main/css/css-layout/practical-positioning-examples/info-box.html
https://mdn.github.io/learning-area/css/css-layout/practical-positioning-examples/info-box.html
이 예제는 키보드 접근성 측면에서 잘 작동하며 여러 탭 사이를 자유롭게 이동하고 탭 선택 시 탭의 콘텐츠를 표시할 수 있습니다. 또한 화면에서 무슨 일이 일어나고 있는지 볼 수 없더라도 콘텐츠를 스크롤하고 제목을 사용해 탐색할 수 있으므로 접근성이 상당히 뛰어납니다. 그러나 현재 스크린 리더는 콘텐츠를 링크 목록으로 표시하고 일부 콘텐츠는 제목이 3개로 표시되는 등 콘텐츠가 무엇인지 명확하게 보이지 못합니다. 콘텐츠 간에 어떤 관계가 있는지 전혀 알 수 없습니다. 사용자에게 콘텐츠 구조에 대한 더 많은 단서를 제공하는 것은 언제나 좋은 일입니다.
이를 개선하기 위해 aria-tabbed-info-box.html이라는 새로운 버전의 예제를 만들었습니다. 탭 인터페이스 구조를 다음과 같이 업데이트했습니다.
https://mdn.github.io/learning-area/accessibility/aria/aria-tabbed-info-box.html
<ul role="tablist">
<li
class="active"
role="tab"
aria-selected="true"
aria-setsize="3"
aria-posinset="1"
tabindex="0">
Tab 1
</li>
<li
role="tab"
aria-selected="false"
aria-setsize="3"
aria-posinset="2"
tabindex="0">
Tab 2
</li>
<li
role="tab"
aria-selected="false"
aria-setsize="3"
aria-posinset="3"
tabindex="0">
Tab 3
</li>
</ul>
<div class="panels">
<article class="active-panel" role="tabpanel" aria-hidden="false">…</article>
<article role="tabpanel" aria-hidden="true">…</article>
<article role="tabpanel" aria-hidden="true">…</article>
</div>
여기서 가장 눈에 뜨는 변화는 원래 예제에서 링크를 제거하고 목록 항목만 탭으로 사용했다는 점입니다. 이렇게 하면 스크린 리더 사용자의 혼란을 줄이고(기존 링크가 어딘가 이동하기 위한 용도가 아니라 보기 대상만 변경했던 것이라) setsize/position 기능이 좀 더 잘 동작하게 합니다. 링크를 사용했을 때 브라우저는 "3의 1", "3의 2"가 아니라 항상 "1의 1"로 정보를 제공했었습니다.
사용한 ARIA 기능은 다음과 같습니다.
- 새로운 role: tablist, tab, tabpanel - 탭 인터페이스의 중요한 영역인 탭 컨테이너, 탭, 탭 패널을 식별합니다.
- aria-selected: 현재 선택된 탭을 정의합니다. 사용자가 다른 탭을 선택하면 다른 탭의 이 속성값이 자바스크립트를 통해 업데이트됩니다.
- aria-hidden: 스크린 리더가 해당 요소를 읽지 못하도록 숨깁니다. 사용자가 다른 탭을 선택하면 다른 탭의 이 속성값이 자바스크립트를 통해 업데이트됩니다.
- tabindex="0": 링크를 제거했으므로 목록 항목에서 이 속성을 부여해 키보드 포커스를 제공해야 합니다.
- aria-setsize: 이 속성을 사용하면 스크린 리더에 요소가 상위 그룹의 일부임을 지정하고 상위 그룹에 포함된 항목 수를 지정할 수 있습니다.
- aria-posinset: 이 속성을 사용하면 요소의 상위 그룹에서 자신의 위치를 지정할 수 있습니다. aria-setsize와 함께 사용해서 현재 "3의 1" 항목에 있다는 식의 충분한 정보를 스크린 리더에게 제공할 수 있습니다. 대부부느이 경우 브라우저는 요소 계층 구조에서 이런 정보를 유추할 수 있어야 하지만 더 많은 단서를 제공하는데 도움이 됩니다.
테스트 결과 새로운 구조가 전반적인 개선이 된 것을 확인할 수 있습니다. 이제 탭이 탭으로 인식되고(스크린 리더에서 "탭"이라고 읽어줍니다) 선택한 탭은 탭 이름과 함께 "선택됨"으로 표시되며, 스크린 리더에서 현재 어떤 탭 위치에 있는지도 알려줍니다. 또한 aria-hidden 설정(숨김 되지 않은 탭만 aria-hidden="false"로 설정)으로 숨김 되지 않는 콘텐츠만 아래로 탐색할 수 있어 선택한 콘텐츠를 더 쉽게 찾을 수 있습니다.
스크린 리더가 읽지 않기를 원하는 내용이 있는 경우 aria-hidden="true" 속성을 지정할 수 있습니다.
여러분의 실력을 테스트하세요.
이 글을 끝까지 읽고 나서 가장 중요한 정보를 기억할 수 있나요? 다음 단계로 넘어가기 전에 이 정보를 잘 기억하고 있는지 확인할 수 있는 몇 가지 추가 테스트가 있으니, 여러분의 실력을 테스트해 보세요.
요약
이 글에서 WAI-ARIA의 모든 기능을 다룬 것은 아니지만 사용 방법을 이해하고 이를 필요로 하는 가장 일반적인 패턴 몇 가지를 파악하는 데 충분한 정보를 제공했을 겁니다.