접근성을 고려하여 javascript 작성하기
✨접근성을 고려하여 javascript 작성하기
원글: https://medium.com/@matuzo/writing-javascript-with-accessibility-in-mind-a1f6a5f467b9
📖목차
- 좋은 포커스 관리의 중요성
- 버튼을 만들 때는
button
요소를 사용하라 - 동적으로 내용이 변경될 때 스크린 리더 사용자에게 알릴 것
- 위젯이 제공해야하는 사용 패턴 추측하지 말 것
1. 좋은 포커스 관리의 중요성
키보드를 사용하여 웹 사이트를 탐색하도록 하는 것은 중요합니다. 많은 사람들이 웹 서핑을 할 때 키보드를 사용합니다. 그들 중에는 운동 장애가 있는 사람, 시각 장애인, 손이 없거나 어떤 이유로든 마우스나 트랙 패드를 사용할 수 없는 사람들도 포함됩니다.
키보드를 사용해 사이트를 탐색한다는 것은 초점이 맞춰진 요소에서 다른 요소로 DOM 순서대로 이동하는 것을 의미합니다. 이 작업은 일반적으로 Tab
키 또는 반대 방향의 경우 Shift + Tab
키를 사용합니다. 포커스가 가능한 요소에는 링크, 버튼, 폼 양식 등이 있습니다. 이러한 요소는 Enter
키와 Space Bar
를 사용하여 선택할 수 있습니다. 다양한 방식으로 초점을 맞추고 선택할 수 있으므로 유용한 기능들이 기본적으로 제공됩니다. 따라서 올바른 의미 요소를 사용하고 논리적 순서대로 HTML를 작성하는 것이 좋습니다.
<p>
, <h2>
, <div>
와 같은 요소는 기본적으로 초점을 맞출 수 없습니다. 이러한 태그를 사용하여 자바스크립트로 구동되는 사용자 정의 컴포넌트를 만드는 경우가 많은데, 키보드 사용자에게는 문제가 될 수 있습니다.
✅focus 되지 않는 요소를 focus가 되는 요소로 만들기
tabindex
를 사용하면 focus할 수 없는 요소를 focus할 수 있게 만들어줍니다. 값이 0으로 설정되면 요소에 focus
를 맞출 수 있고 키보드를 통해 접근할 수 있습니다.
값이 음수인 경우, 요소에 focus
을 맞출 수 있지만 키보드로는 도달할 수 없습니다.
0보다 큰 값을 사용할 수도 있지만, 이 경우 탭 순서가 변경되기 때문에 안티 패턴으로 간주됩니다.
1
<h2 tabindex="0">A focusable heading</h2>
tabindex
에 자세히 알아보고 싶으면 the A11ycasts episode Controlling focus with tabindex 영상을 시청하세요.
✅ 자바스크립트를 사용해서 focus 맞추기
요소에 focus를 맞추더라도 올바른 DOM 순서가 아닌 경우가 있습니다. 이를 설명하기 위해 HTML,CSS,JS로 간단한 모달 창 컴포넌트를 만들었습니다.
Tab
키를 사용하여 버튼으로 이동하고 Enter
키를 누르면 모달창이 나타납니다. Tab
키를 다시 누르면 초점이 모달창 아래 다음 링크로 이동합니다. 모달창 안에 있는 요소에 초점이 맞춰지는 것이 예상되는 동작입니다. 하지만 요소는 DOM 순서대로 초점이 맞춰지고 모달창은 문서 하단에 위치하기 때문에 그렇지 않습니다. 다음 화면 녹화에서 실제로 작동하는 것을 확인할 수 있습니다.
이 문제를 해결하려면 모달 창에 초점을 맞출 수 있도록 설정한 다음 자바스크립트로 초점을 맞춰야 합니다.
HTML
1
2
<!-- tabindex="0" 추가하기 -->
<div class="modal" id="modal2" tabindex="0">...</div>
javascript
1
2
3
4
5
6
7
// focus 메소드를 사용해서 focus 시키기
function showModal() {
...
var modal = document.getElementById('modal2');
modal.focus();
...
}
업데이트된 예제에서 버튼을 Tab
하고 Enter
키를 누른 다음 다시 Tab
을 하면 실제로 작동하는 것을 확인할 수 있습니다. 이제 모달창 자체에 포커스가 맞춰진 것을 볼 수 있습니다.
이것은 훌륭하긴 하지만 여전히 두 개의 문제점을 가지고 있습니다.
Esc
키를 눌러 모달창을 닫으면 포커스가 손실됩니다. 포커스가 모달창을 열기 전에 있었던 버튼으로 되돌아가는 것이 가장 이상적입니다. 이를 위해서는 마지막으로 초점을 맞춘 요소를 변수에 저장해야합니다.
document.activeElement
는 현재 초점이 맞춰진 요소를 제공합니다.
1
2
3
4
5
6
7
8
9
10
// 마지막으로 포커스된 요소를 저장하기 위한 변수
var lastFocusedElement;
function showModal() {
...
// 마지막으로 포커스된 요소 저장
lastFocusedElement = document.activeElement;
var modal = document.getElementById(modalID);
modal.focus();
...
}
이제 버튼에 대한 참조가 생겼으므로 모달창이 닫힐 때 다시 초점을 맞출 수 있습니다.
1
2
3
4
5
6
function removeModal() {
...
// 마지막으로 포커스된 요소에 다시 포커스 시키기
lastFocusedElement.focus();
...
}
다른 Codepen에 해당 코드를 업데이트 했습니다. 지금은 접근성이 훨씬 좋아졌지만, 여전히 개선의 여지가 남아있습니다.
모달창이 열렸을 때 포커스를 모달창 안에 유지하는 것이 좋습니다. 지금은 모달창 밖으로 탭할 수 있습니다.
여기서는 자세히 설명하지 않겠지만 완성도를 높이기 위해 키보드 트랩이 있는 네번째 Codepen을 만들었습니다. 모달창이 활성화되어 있는 한 포커스는 모달창 내에 유지됩니다.
첫번째 Codepen과 마지막 Codepen을 비교해보면 추가 코드가 많지 않다는 것을 확인할 수 있습니다. 완벽하지는 않지만 최종 솔루션을 사용하기에 훨씬 좋습니다.
접근성 모달에 대한 또 다른 예제와 구글에서 작성한 Tabindex
사용이라는 훌륭한 문서가 있습니다.
키보드 테스트에 대해 자세히 알아보려면 WebAIM 웹사이트에 방문하세요. “가장 일반적인 온라인 상호작용 목록, 상호작용을 위한 표준 키 입력, 테스트 시 고려해야할 사항에 대한 추가 정보”를 제공합니다. 포커스 관리에 대한 더 많은 예시를 보려면 egghead.io 동영상 Focus management using CSS, HTML, and JavaScript 또는 the A11ycasts episode What is Focus?를 확인하세요.
2. 버튼을 만들 때는 button
요소를 사용하라
첫 번째 글에서 버튼에 대해 이미 썼지만 많은 사람들이 일반적인 요소를 button
으로 사용하는 것 같습니다. 그래서 그 주제에 대해 좀 더 써도 나쁘지 않을 것 같습니다.
저는 버튼이나 입력 요소 대신에 span
이나 div
를 사용할 때 발생하는 몇 가지 문제를 설명하기 위해 Codepen을 작성했습니다. 페이지를 Tab
하면 첫번째 버튼에는 초점을 맞출 수 있지만 두번째 버튼에는 초점을 맞출 수 없는 것을 경험할 수 있습니다. 당연히 첫번째 버튼은 button
요소이고, 두번째 버튼은 div
요소이기 때문입니다. 먼저 div
요소에 tabindex = "0"
을 추가하면 이 문제를 해결할 수 있습니다. 그래서 세번째 네번째 버튼은 div
임에도 불구하고 초점을 맞출 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
<!-- 버튼, 포커스 가능 -->
<button class="btn">I'm a button</button>
<!-- div, 포커스 불가능 -->
<div class="btn">I'm a div</div>
<!-- div, 포커스 가능 -->
<div class="btn" tabindex="0">I'm a div</div>
<!-- 버튼 역할, 포커스 가능 -->
<div class="btn" tabindex="0" role="button">I'm a div</div>
div-button
은 실제로 포커스가 가능하지만 role="button"
을 추가하더라고 여전히 div
처럼 동작합니다. 이를 설명하기 위해 모든 .btn
에 간단한 클릭 이벤트 핸들러를 추가했습니다. (Codepen) 버튼을 클릭하면 경고 상자가 나타나지만 키(Enter
또는 Space Bar
)를 사용하여 동일한 작업을 시도하면 첫번째 버튼만 이벤트가 트리거 됩니다. 기본 버튼 요소를 완전히 모방하려면 div-button
에 키 이벤트 핸들러를 추가해야 합니다. 이는 불필요한 오버헤드처럼 보입니다. 그렇지 않나요? 따라서 버튼이 필요한 경우 button
요소를 사용해야 합니다.
Rob Dodson의 “Just use button” A11ycasts”를 시청하거나 Adrian Roselli의 “Links, Buttons, Submits, and Divs, Oh Hell”를 읽어 자세한 내용과 예제를 확인하세요
3. 동적으로 내용이 변경될 때 스크린 리더 사용자에게 알릴 것
보통 스크린 리더는 요소가 포커스 받거나 사용자가 스크린 리더 내비게이션 명령을 사용할 때만 콘텐츠를 알립니다. 콘텐츠가 동적으로 로드되어 DOM에 삽입되는 경우 시력이 있는 사용자만 변경사항을 인식하게 됩니다. ARIA Live Regions에서는 이 문제를 해결할 수 있는 몇 가지 옵션을 제공합니다. 예시를 통해 그 방법을 보여드리겠습니다. 저장버튼을 클릭하면 페이지를 다시 로드하지 않고 변경사항이 저장됩니다. 변경사항이 성공적으로 적용되었는지 여부는 알림을 통해서 사용자에게 알려줍니다. 이 알림은 즉시 표시되거나 시간이 걸릴 수도 있습니다. 방금 설명한 내용을 보여드리기 위해 간단한 동영상을 녹화했습니다.
작업이 성공한 것처럼 보여지지만 소리가 들리지 않습니다. 스크린 리더 사용자는 변경사항을 알아차리지 못하지만 이 문제에 대한 간단한 해결책이 있습니다. 메세지 상자에 role="status"
또는 alert
를 추가하면 스크린 리더가 해당 요소의 콘텐츠 업데이트를 수신합니다.
1
<div class="message" role="status">Changes saved!</div>
메세지 텍스트가 변경되면 새 텍스트가 읽혀집니다. 비디오에서 변경된 내용을 확인할 수 있으며 Codepen에서 코드를 확인할 수 있습니다.
✅사용자에게 예의 지키기
알림은 스크린 리더가 다른 내용을 발표하는 중일 경우 스크린 리더를 방해하지만 상태는 스크린 리더가 발표를 마칠 때까지 기다린다는 것이 다릅니다.
aria-live라는 또 다른 속성이 있는데, 이 속성은 3가지의 값을 사용할 수 있습니다. 기본값은 off이며, aria-live="polite"
은 role="status"
와 동등하고,aria-live="assertive"
은 role="alert"
와 동등합니다. “잘 알려진 미리 정의된 경우에는 특정 ‘라이브 지역 역할’을 사용하는 것이 좋습니다. 또한 브라우저가 역할을 지원하지 않는 경우 두 가지 속성을 모두 사용해 볼 수도 있습니다. Léonie Watson이 Screen reader support for ARIA live regions에 몇 가지 테스트 결과를 공유했습니다.
1
<div role="alert" aria-live="assertive"></div>
✅ 때로는 변경된 콘텐츠 그 이상을 발표하는 것이 합리적입니다.
기본적으로 스크린 리더는 동일한 라이브 영역 내에 다른 콘텐츠가 있더라도 변경된 콘텐츠만 표시하지만 전체 텍스트를 알리는 것이 합리적인 경우도 있습니다.
aria-atomic
속성을 사용하면 기본 동작을 변경할 수 있습니다. true
를 설정하면 보조 기술이 요소의 전체 콘텐츠를 표시합니다.
다양한 라이브 지역 설정을 비교하는 Paul J. Adam의 aria-atomic 테스트 사례 데모가 있습니다. iOS 8.1에서 보이스오버를 사용하여 데모를 테스트하고 이를 녹화하여 실제로 볼 수 있도록 했습니다. aria-atomic
에 대해 더 잘 이해하고 싶으시다면 이 영상을 시청해보세요. VoiceOver iOS 8.1 Speaking Characters Remaining aria-atomic & aria-relevant on aria-live regions
또한 그는. 아리아 원자 사용 사례를 더 잘 이해하고 싶으시다면 이 녹화 자료(iOS 8.1에서 음성으로 말하는 문자가 아리아 원자 및 아리아 라이브 지역에서 아리아 관련성을 유지)를 시청해 보시기 바랍니다.
✅ 몇 가지 고려할 사항
- 라이브 지역은 포커스를 이동하지 않고 텍스트 알림만 트리거합니다.
- 중요한 변경 사항에만 알림을 사용하세요. 대부분의 경우 상태 알림이 더 좋습니다.
- 알림이 너무 빨리 사라질 수 있으므로 자동으로 사라지는 알림은 디자인하지 마세요.
- 테스트하는 동안 보이스오버에 문제가 있었습니다. CSS를 사용하여 알림을 숨기거나 동적으로 생성해도 항상 작동하지 않았습니다. 다른 소프트웨어로 다른 브라우저에서 라이브 지역을 철저히 테스트해야 합니다.
물론, 자세한 내용과 예제는 A11ycasts episode “Alerts!“ by Rob Dodson에서 확인할 수 있습니다. Heydon Pickering 에 라이브 지역에 대한 또 다른 예제가 있습니다.
4. 위젯이 제공해야하는 사용 패턴 추측하지 말 것
위젯이 탐색 및 접근성 측면에서 제공해야 하는 모든 기능을 생각하기는 쉽지 않습니다. 다행히도 “WAI-ARIA Authoring Practices 1.1”라는 리소스가 있어 도움이 됩니다. “WAI-ARIA 저작 사례”는 접근성 높은 리치 인터넷 애플리케이션을 만들기 위해 “WAI-ARIA”를 사용하는 방법을 이해하기 위한 안내서입니다. 권장되는 “WAI-ARIA” 사용 패턴을 설명하고 그 이면에 있는 개념을 소개합니다.
아코디언, 슬라이더, 탭 등을 만들기 위한 가이드가 있습니다.
5. 접근 가능한 자바스크립트 구성 요소
접근 가능한 자바스크립트 구성 요소가 포함된 훌륭한 리소스도 있습니다.
- 실용적인 ARIA 예제
- 모달 - WCAG 2.0 레벨 AA 접근성 모달 창 플러그인
- Frend - 접근 가능한 최신 프런트엔드 컴포넌트 모음
- A11Y 프로젝트 패턴
요약
자바스크립트의 장점을 활용하여 사이트의 접근성을 개선하세요. 포커스 관리에 신경 쓰고, 일반적인 사용 패턴을 파악하고, DOM을 조작할 때 스크린 리더 사용자를 고려하세요. 무엇보다 누구를 위해 웹 사이트를 만들고 있는지 잊지 마세요.