접근 가능한 탭 버튼을 만드는 것은 모든 사용자가 사용할 수 있도록 하기 위해 여러 모범 사례를 따르는 것입니다. 여기에는 장애가 있는 사용자를 포함합니다. 다음은 WCAG 표준을 준수하는 접근 가능한 탭 버튼을 만드는 가이드입니다:
1. 의미론적 HTML 및 ARIA 역할 사용
보조 기술에 탭 구조를 전달하기 위해 의미론적 HTML 요소와 ARIA (Accessible Rich Internet Applications) 역할을 사용합니다.
<div role="tablist" aria-label="예제 탭">
<button role="tab" aria-selected="true" aria-controls="panel1" id="tab1">탭 1</button>
<button role="tab" aria-selected="false" aria-controls="panel2" id="tab2">탭 2</button>
<button role="tab" aria-selected="false" aria-controls="panel3" id="tab3">탭 3</button>
</div>
<div role="tabpanel" id="panel1" aria-labelledby="tab1">
<p>탭 1의 내용입니다.</p>
</div>
<div role="tabpanel" id="panel2" aria-labelledby="tab2" hidden>
<p>탭 2의 내용입니다.</p>
</div>
<div role="tabpanel" id="panel3" aria-labelledby="tab3" hidden>
<p>탭 3의 내용입니다.</p>
</div>
2-1. 탭 선택 기능 구현
탭 선택에 따른 컨텐츠 변경 및 탭 버튼의 속성 변경 내용을 코드로 작성하도록 합니다. 제이쿼리 등을 활용하면 더 간단하게 작성할 수 있고, 또한 접근성 준수를 위해 꼭 아래 코드의 전체를 적용해야 하는 것은 아닙니다.
document.addEventListener('DOMContentLoaded', function() {
const tabList = document.querySelector('[role="tablist"]');
const tabs = tabList.querySelectorAll('[role="tab"]');
const tabPanels = document.querySelectorAll('[role="tabpanel"]');
tabs.forEach(tab => {
tab.addEventListener('click', function() {
// Deselect all tabs and hide all tab panels
tabs.forEach(t => {
t.setAttribute('aria-selected', 'false');
t.setAttribute('tabindex', '-1');
});
tabPanels.forEach(panel => panel.setAttribute('hidden', 'true'));
// Select the clicked tab and show the associated panel
tab.setAttribute('aria-selected', 'true');
tab.removeAttribute('tabindex');
const panelId = tab.getAttribute('aria-controls');
document.getElementById(panelId).removeAttribute('hidden');
});
tab.addEventListener('keydown', function(event) {
let newTab;
switch (event.key) {
case 'ArrowLeft':
case 'ArrowUp':
newTab = tab.previousElementSibling;
break;
case 'ArrowRight':
case 'ArrowDown':
newTab = tab.nextElementSibling;
break;
case 'Home':
newTab = tabs[0];
break;
case 'End':
newTab = tabs[tabs.length - 1];
break;
default:
return;
}
if (newTab) {
newTab.focus();
newTab.click();
}
});
});
// Set up the initial state
const selectedTab = tabList.querySelector('[aria-selected="true"]');
if (selectedTab) {
selectedTab.setAttribute('tabindex', '0');
document.getElementById(selectedTab.getAttribute('aria-controls')).removeAttribute('hidden');
} else {
// If no tab is selected, select the first one by default
tabs[0].setAttribute('aria-selected', 'true');
tabs[0].setAttribute('tabindex', '0');
document.getElementById(tabs[0].getAttribute('aria-controls')).removeAttribute('hidden');
}
});
2-2. 키보드 상호작용 관리 (선택)
탭 버튼이 키보드로 탐색할 수 있도록 합니다. 사용자는 화살표 키를 사용하여 탭 간을 탐색하고 Enter 또는 Space 키를 사용하여 탭을 활성화할 수 있어야 합니다. 이 부분은 선택적으로 진행해도 되는 이유는 스크린리더가 클릭 이벤트는 자동으로 전용 커맨드로 선택이 가능하게 설정될 수 있기 때문입니다.
document.querySelectorAll('[role="tab"]').forEach(tab => {
tab.addEventListener('keydown', e => {
let newTab;
switch (e.key) {
case 'ArrowLeft':
case 'ArrowUp':
newTab = tab.previousElementSibling || tab.parentElement.lastElementChild;
break;
case 'ArrowRight':
case 'ArrowDown':
newTab = tab.nextElementSibling || tab.parentElement.firstElementChild;
break;
case 'Enter':
case ' ':
activateTab(tab);
break;
default:
return;
}
newTab.focus();
});
tab.addEventListener('click', () => activateTab(tab));
});
function activateTab(tab) {
document.querySelectorAll('[role="tab"]').forEach(t => {
t.setAttribute('aria-selected', false);
document.getElementById(t.getAttribute('aria-controls')).hidden = true;
});
tab.setAttribute('aria-selected', true);
document.getElementById(tab.getAttribute('aria-controls')).hidden = false;
tab.focus();
}
3. 시각적 포커스 표시 제공
키보드로 탐색하는 사용자를 위해 포커스 표시가 눈에 띄도록 합니다.
[role="tab"]:focus {
outline: 2px solid blue;
outline-offset: 2px;
}
4. ARIA 속성 사용
ARIA 속성을 사용하여 탭과 해당하는 탭 패널 간의 관계를 정의하고, 탭의 선택 상태를 나타냅니다.
role="tablist"
: 탭 세트를 정의하는 컨테이너입니다.role="tab"
: 각 탭을 정의합니다.aria-controls
: 연관된 탭 패널을 식별합니다.aria-selected
: 현재 선택된 탭을 나타냅니다.role="tabpanel"
: 탭의 콘텐츠 패널을 정의합니다.aria-labelledby
: 패널을 해당 탭과 연결합니다.
5. 적절한 헤딩 구조 보장
각 탭 패널 내부에 적절한 헤딩을 사용하여 사용자가 콘텐츠 구조를 이해할 수 있도록 합니다.
<div role="tabpanel" id="panel1" aria-labelledby="tab1">
<h2>탭 1의 내용</h2>
<p>탭 1의 내용입니다.</p>
</div>
6. 상태 변경 시 접근성 유지
상태 변경(예: 탭 패널 표시/숨기기)이 접근 가능하도록 합니다. 예를 들어, hidden
속성을 사용하여 비활성 탭 패널을 숨깁니다.
접근 가능한 탭 예제
<div role="tablist" aria-label="예제 탭">
<button role="tab" aria-selected="true" aria-controls="panel1" id="tab1">탭 1</button>
<button role="tab" aria-selected="false" aria-controls="panel2" id="tab2">탭 2</button>
<button role="tab" aria-selected="false" aria-controls="panel3" id="tab3">탭 3</button>
</div>
<div role="tabpanel" id="panel1" aria-labelledby="tab1">
<h2>탭 1의 내용</h2>
<p>탭 1의 내용입니다.</p>
</div>
<div role="tabpanel" id="panel2" aria-labelledby="tab2" hidden>
<h2>탭 2의 내용</h2>
<p>탭 2의 내용입니다.</p>
</div>
<div role="tabpanel" id="panel3" aria-labelledby="tab3" hidden>
<h2>탭 3의 내용</h2>
<p>탭 3의 내용입니다.</p>
</div>
이러한 모범 사례를 따르면 접근 가능하고 사용자 친화적인 탭 버튼을 만들어 보조 기술을 사용하는 사용자도 효과적으로 콘텐츠와 상호작용할 수 있습니다.
'정보 접근성 > 접근성 (A11Y) - 컴포넌트' 카테고리의 다른 글
접근성 준수 컴포넌트 - 이미지 (테이블 대체 텍스트 만들기) (0) | 2024.07.07 |
---|---|
접근성 준수 컴포넌트 - 앵커 (a, 링크 태그) (0) | 2024.07.05 |
접근성 준수 컴포넌트 - 이미지 (0) | 2024.07.05 |
접근성 준수 컴포넌트 - 이미지 (텍스트가 많은 이미지) (0) | 2024.07.05 |
접근성 준수 컴포넌트 - 테이블 (Table) (0) | 2024.07.03 |