Front-end/Accessibility

[웹접근성]웹접근성을 고려한 탭메뉴 만들기

by 빽짱구 2024. 7. 19.

웹 접근성을 고려한 탭 메뉴는 키보드 사용자, 스크린 리더 사용자 등 다양한 사용자들이 접근할 수 있도록 구성해야 합니다.

탭 메뉴 구성 요소

  1. 탭 컨테이너: 탭 메뉴를 감싸는 컨테이너.
  2. 탭 리스트: 각 탭 버튼을 포함하는 리스트.
  3. 탭 버튼: 클릭 또는 키보드로 선택할 수 있는 버튼.
  4. 탭 패널: 각 탭 버튼이 활성화될 때 보여줄 콘텐츠.

접근성을 고려한 HTML 구조

다음은 웹 접근성을 고려한 탭 메뉴의 기본 HTML 구조입니다.

<div class="tab-container" role="tablist" aria-label="샘플 탭">
    <button role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1">탭 1</button>
    <button role="tab" aria-selected="false" aria-controls="panel-2" id="tab-2">탭 2</button>
    <button role="tab" aria-selected="false" aria-controls="panel-3" id="tab-3">탭 3</button>
</div>

<div id="panel-1" role="tabpanel" aria-labelledby="tab-1">
    <p>탭 1의 내용</p>
</div>
<div id="panel-2" role="tabpanel" aria-labelledby="tab-2" hidden>
    <p>탭 2의 내용</p>
</div>
<div id="panel-3" role="tabpanel" aria-labelledby="tab-3" hidden>
    <p>탭 3의 내용</p>
</div>

HTML 구조

  • role="tablist": 탭 버튼들을 감싸는 컨테이너로 역할을 지정합니다.
  • role="tab": 각각의 탭 버튼에 역할을 지정합니다.
  • role="tabpanel": 각각의 탭 패널에 역할을 지정합니다.
  • aria-selected: 현재 선택된 탭을 나타냅니다.
  • aria-controls: 이 탭이 제어하는 패널을 지정합니다.
  • aria-labelledby: 이 패널이 관련된 탭을 지정합니다.
  • hidden: 현재 보이지 않는 패널을 숨깁니다.

CSS

/* 탭 컨테이너 스타일 */
.tab-container {
    display: flex;
}

/* 각 탭 버튼 스타일 */
[role="tab"] {
    padding: 10px;
    cursor: pointer;
    background-color: #f1f1f1;
    border: 1px solid #ccc;
    margin-right: -1px;
}

/* 탭 버튼에 포커스 또는 마우스를 올렸을 때 스타일 */
[role="tab"]:focus, [role="tab"]:hover {
    background-color: #ddd;
}

/* 선택된 탭 버튼 스타일 */
[role="tab"][aria-selected="true"] {
    background-color: #ccc;
    border-bottom: none;
}

/* 탭 패널 스타일 */
[role="tabpanel"] {
    padding: 10px;
    border: 1px solid #ccc;
    border-top: none;
}

/* 숨겨진 탭 패널 스타일 */
[role="tabpanel"][hidden] {
    display: none;
}

CSS는 참고만 하셔도 됩니다.

JavaScript로 탭 동작 구현

document.addEventListener('DOMContentLoaded', function() {
    const tabs = document.querySelectorAll('[role="tab"]');
    const tabList = document.querySelector('[role="tablist"]');

    let tabFocus = 0;

    // 키보드로 탭 이동 기능 구현
    tabList.addEventListener('keydown', function(e) {
        const keydownLeft = 37;
        const keydownRight = 39;

        // 왼쪽 화살표 키로 이동
        if (e.keyCode === keydownLeft) {
            tabs[tabFocus].setAttribute("tabindex", -1);
            if (tabFocus === 0) {
                tabFocus = tabs.length - 1;
            } else {
                tabFocus--;
            }
        }
        // 오른쪽 화살표 키로 이동
        else if (e.keyCode === keydownRight) {
            tabs[tabFocus].setAttribute("tabindex", -1);
            if (tabFocus === tabs.length - 1) {
                tabFocus = 0;
            } else {
                tabFocus++;
            }
        }

        tabs[tabFocus].setAttribute("tabindex", 0);
        tabs[tabFocus].focus();
    });

    // 탭 클릭 시 탭 변경
    tabs.forEach(tab => {
        tab.addEventListener('click', changeTabs);
    });

    // 탭을 변경하는 함수
    function changeTabs(e) {
        const target = e.target;
        const parent = target.parentNode;
        const grandparent = parent.parentNode;

        // 현재 선택된 탭 제거
        parent
            .querySelectorAll('[aria-selected="true"]')
            .forEach(t => t.setAttribute('aria-selected', 'false'));

        // 선택된 탭 설정
        target.setAttribute('aria-selected', 'true');

        // 모든 탭 패널 숨기기
        grandparent
            .querySelectorAll('[role="tabpanel"]')
            .forEach(p => p.setAttribute('hidden', 'true'));

        // 선택된 탭 패널 보이기
        grandparent.parentNode
            .querySelector(`#${target.getAttribute('aria-controls')}`)
            .removeAttribute('hidden');
    }
});

JavaScript 동작

  • 키보드 왼쪽/오른쪽 화살표 키로 탭을 이동할 수 있도록 이벤트를 추가합니다.
  • 탭 클릭 시, 현재 선택된 탭을 갱신하고, 해당 탭의 패널을 표시합니다.

사실 html과 javascript만 살펴보셔도 됩니다.

728x90