WAI-ARIA
웹 개발을 할 때 편리한 레이아웃을 셋팅하여 사용성과 편의성을 증진시키는 것도, 화려한 화면과 인터렉션을 통해 살아움직이면서도 아름다운 사이트를 만드는 것도 웹 페이지에 접근하는 사용자에게 흥미를 유발하는 점에서 중요하지만, 간과하지 말아야 하는 점은 스크린 리더 및 보조도구를 사용하는 사용자의 웹 접근성을 보장하는 일인 것 같다. 특히, 아무런 의미 없는 태그인 <div> ,<span> 의 무분별한 사용은 스크린 리더를 사용하는 사용자에게 웹 페이지의 유의미한 정보를 제공해주지 못하기 때문에 되도록 사용을 지양하는 것이 좋다고 하는데, 그럼에도 불구하고 사용해야 하는 상황에서는 웹 접근성을 향상시키기 위해 사용되는 WAI-ARIA (Web Accessibility Initiative - Accessible Rich Internet Applications) 속성을 적용하면, 사용자의 웹 접근성을 보장할 수 있다.
WAI-ARIA |
웹 애플리케이션과 동적 콘텐츠에 접근성을 제공하는 데 사용되는 기술 표준이다. 이 표준은 레이블, 롤, 상태, 속성 등을 포함하는 다양한 속성을 제공하여 웹 페이지나 웹 애플리케이션의 요소에 의미를 부여하고 접근성을 향상시킨다. |
오늘 정리하고자 하는 aria-controls 이라는 속성도 이 중 하나이며, 흔히 모달창, 체크박스, 탭 메뉴 등을 사용하는 콘텐츠에 대한 웹 접근성을 높이기 위해 사용될 수 있다.
aria-controls
우선 aria-controls 를 지정하는 요소(태그)는 특정 컴포넌트가 눈에 보이게 하거나, 안 보이게 하기 위해 사용하는 버튼 등에 지정한다. 예를 들어, tab1, tab2, tab3 이라는 탭 요소들이 있을 때 tab1 을 클릭하면 tab1 과 관련한 내용이 화면에 표시되고, tab2 를 클릭하면 tab2와 관련된 내용이 표시되는데, 이 때 해당 탭 요소(태그)의 속성에 aria-controls 를 적용한다.
<div role="tablist">
<!-- 탭 버튼 목록 -->
<button role="tab" aria-controls="tab-content-1" class="tab-button" tabindex="0">Tab 1</button>
<button role="tab" aria-controls="tab-content-2" class="tab-button" tabindex="0">Tab 2</button>
<button role="tab" aria-controls="tab-content-3" class="tab-button" tabindex="0">Tab 3</button>
</div>
위 예시를 보면 tab 역할(role)를 부여 받은 button 요소의 속성으로 aria-controls 를 지정한 것을 볼 수 있는데, 여기서 해당 속성의 값으로 tab-content-1 .. 이 입력되어 있다.
<!-- 탭 내용 -->
<div id="tab-content-1" role="tabpanel" class="tab-content">
<p>This is the content for Tab 1.</p>
</div>
<div id="tab-content-2" role="tabpanel" class="tab-content">
<p>This is the content for Tab 2.</p>
</div>
<div id="tab-content-3" role="tabpanel" class="tab-content">
<p>This is the content for Tab 3.</p>
</div>
앞서 aria-controls 의 값으로 지정된 tab-content-1.. 은 위와 같이 탭의 내용을 표시하는 요소를 식별하는 데 사용되며, 탭 버튼과 내용 사이의 관계를 식별하는 데 id 속성의 값과 탭 버튼의 aria-controls 속성의 값이 일치하는 지 여부로 판단한다. 즉, 스크린 리더 및 보조기기를 통해 사용자가 해당 요소에 접근하게 되면, 스크린 리더는 해당 탭 버튼과 탭 내용 간의 관계를 파악하고, 사용자에게 특정 탭을 클릭 시 보여지는 탭 내용을 읽어서 전달하게 된다.
만약에 div 와 button 태그에 아무런 속성이 지정되어 있지 않다면 어떻게 될까? 시각적으로 문제가 없는 사람은 해당 내용을 바로 식별해서 어떤 역할을 하는 것인지 파악할 수 있겠으나, 음성을 통해서 해당 탭과 내용을 파악해야 하는 사용자 입장에서는 파악하기 매우 어려울 것이다.
그런데, 해당 탭 메뉴가 선택되었는지는 어떻게 분간할까?
여기 까지 따라왔다면 한 가지 의문이 들 수 있다. 그럼 스크린 리더는 선택된 탭 내용이 무엇인지 어떻게 식별할까? 앞서 예시대로만 본다면, 스크린 리더는 어떤 탭 내용이 활성화 되어있는지 파악하기 어렵다. 즉, aria-controls 와 해당 내용의 id 를 일치시킨다면 탭 버튼과 해당 내용 간에 연관성은 인지할 수 있으나 사용자가 각 버튼을 클릭 했을 때 무엇이 활성화되어있는지는 파악하기 어렵다. 따라서 이 때 활성화 사실을 전달할 수 있도록 돕는 속성이 바로 aria-selected 속성이다.
aria-selected
aria-selected 는 값으로 false 와 true 을 가지는데, false 라면 비활성화, true 라면 활성화되어 있음을 스크린리더가 인식하도록 돕는다.
<!-- 탭 내용 -->
<div id="tab-content-1" role="tabpanel" class="tab-content">
<p>This is the content for Tab 1.</p>
</div>
<div id="tab-content-2" role="tabpanel" class="tab-content">
<p>This is the content for Tab 2.</p>
</div>
<div id="tab-content-3" role="tabpanel" class="tab-content">
<p>This is the content for Tab 3.</p>
</div>
여기서 다시 탭 내용을 살펴보면, 이와 같은 형식으로만 존재한다면 스크린 리더는 어떤 탭 내용이 활성화되어 있는지 알 수가 없다.
<div id="tab-content-1" role="tabpanel" class="tab-content" aria-selected="true">
<p>This is the content for Tab 1.</p>
</div>
그러나 위와 같이 aria-selected가 true 로 지정되어 있다면, 스크린리더는 해당 내용을 식별하고 사용자에게 알려줄 수 있다.
이 다음 부터는 자바스크립트를 통해서 동적으로 속성을 값을 전달함으로써 각 탭 버튼을 클릭했을 때 해당 탭 내용이 스크린 리더가 인식하도록 지정할 수 있다.
스크린 리더가 동적으로 탭 내용을 인식하게 하려면
// JavaScript를 사용하여 탭을 관리
const tabButtons = document.querySelectorAll('[role="tab"]');
const tabContents = document.querySelectorAll('[role="tabpanel"]');
tabButtons.forEach((button) => {
button.addEventListener("click", () => {
// 모든 탭 버튼과 탭 콘텐츠를 초기화
tabButtons.forEach((btn) => {
btn.classList.remove("active");
btn.setAttribute("aria-selected", "false");
});
tabContents.forEach((content) => {
content.classList.remove("active");
});
// 선택한 탭 버튼과 연결된 탭 콘텐츠를 활성화
const controlId = button.getAttribute("aria-controls");
const tabContent = document.getElementById(controlId);
button.classList.add("active");
button.setAttribute("aria-selected", "true");
tabContent.classList.add("active");
});
});
위 코드를 보면 각 탭 버튼을 순회하며 'click' 이벤트가 발생하는 순간 선택된 버튼을 제외한 aria-selected 속성의 값을 false 로 지정하고, 선택한 탭 버튼이 가지고 있는 aria-controls와 일치하는 id 값을 가진 탭 내용 요소에 aria-selected 를 true 로 지정하는 것을 볼 수 있다.
이렇게 함으로써 스크린 리더는 사용자가 어떤 탭을 선택했는지, 해당 탭의 내용은 무엇인지를 식별하고 사용자에게 알려줄 수 있게 된다.
포스트에 사용된 코드(전체)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Accessible Tab Menu</title>
<style>
/* 스타일링은 간단한 예시를 위해 최소한으로 유지. */
.tab-button {
cursor: pointer;
padding: 10px 20px;
border: 1px solid #ccc;
background-color: #f0f0f0;
}
.tab-content {
display: none;
padding: 10px;
border: 1px solid #ccc;
}
.tab-content.active {
display: block;
}
</style>
</head>
<body>
<div role="tablist">
<!-- 탭 버튼 목록 -->
<button role="tab" aria-controls="tab-content-1" class="tab-button" tabindex="0">Tab 1</button>
<button role="tab" aria-controls="tab-content-2" class="tab-button" tabindex="0">Tab 2</button>
<button role="tab" aria-controls="tab-content-3" class="tab-button" tabindex="0">Tab 3</button>
</div>
<!-- 탭 내용 -->
<div id="tab-content-1" role="tabpanel" class="tab-content">
<p>This is the content for Tab 1.</p>
</div>
<div id="tab-content-2" role="tabpanel" class="tab-content">
<p>This is the content for Tab 2.</p>
</div>
<div id="tab-content-3" role="tabpanel" class="tab-content">
<p>This is the content for Tab 3.</p>
</div>
<script>
// JavaScript를 사용하여 탭을 관리
const tabButtons = document.querySelectorAll('[role="tab"]');
const tabContents = document.querySelectorAll('[role="tabpanel"]');
tabButtons.forEach((button) => {
button.addEventListener("click", () => {
// 모든 탭 버튼과 탭 콘텐츠를 초기화
tabButtons.forEach((btn) => {
btn.classList.remove("active");
btn.setAttribute("aria-selected", "false");
});
tabContents.forEach((content) => {
content.classList.remove("active");
});
// 선택한 탭 버튼과 연결된 탭 콘텐츠를 활성화
const controlId = button.getAttribute("aria-controls");
const tabContent = document.getElementById(controlId);
button.classList.add("active");
button.setAttribute("aria-selected", "true");
tabContent.classList.add("active");
});
});
</script>
</body>
</html>
포스트에 사용된 코드 구현(결과)
This is the content for Tab 1.
This is the content for Tab 2.
This is the content for Tab 3.
참고자료
https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-selected
https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-controls
'HTML & CSS' 카테고리의 다른 글
[CSS] & | SCSS 를 쓰지 않고도 CSS 도 중첩 사용이 가능하게 해줌 (1) | 2023.12.16 |
---|---|
[HTML] <pickture> | 브라우저 크기에 대한 최적화 용도로 사용하는 이미지 태그 (1) | 2023.12.16 |
[SCSS/SASS] 기초 사용법 정리 (0) | 2023.07.01 |
[html/css] js 코드 없는 아코디언 "클릭하면 스르륵 답변창이 나오는 게시판?" (0) | 2023.02.25 |
[CSS] rem, em 의 차이 (0) | 2023.02.20 |