새로운 질서 위키

마우스와 키보드로 여는 메뉴

하위 하이퍼링크를 접어 두는 메뉴는 열기와 이동을 구분해야 한다. 열고 닫는 동작은 버튼이, 다른 위치로 이동하는 동작은 하이퍼링크가 맡는다. 마우스 없이 읽는 순서에서도 같은 길을 찾을 수 있게 한다.

  • 버튼의 aria-expanded로 펼쳐진 상태를 알리고 aria-controls로 대상 목록을 연결한다.
  • Enter와 Space로 버튼을 누르고, Tab으로 펼쳐진 하이퍼링크를 이동한다. 예제는 Escape로 닫고 버튼으로 돌아간다.
  • 일반적인 웹사이트 탐색에 앱 메뉴용 role="menu"를 붙이지 않는다. 그 역할에는 다른 키보드 동작이 기대된다.
  • 스크립트가 실행되지 않으면 목록을 펼친 채 남긴다. 작동하지 않는 열기 버튼은 보이지 않는다.

작은 예제

아래 코드를 UTF-8 형식의 example-08.html로 저장해 웹 브라우저에서 연다. 가상의 작업 두 종류로 구성한 예제다.

<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>마우스와 키보드로 여는 메뉴</title>
<style>
* { box-sizing: border-box; }
body { margin: 0; padding: 1rem; font-family: sans-serif;
  line-height: 1.6; color: #222; background: #fff; }
main { max-inline-size: 60rem; margin-inline: auto; }
h1 { font-size: 1.7rem; line-height: 1.3; }
a { color: #174fa0; }
:focus-visible { outline: 3px solid #174fa0; outline-offset: 3px; }
button { font: inherit; padding: .5rem .75rem; }
nav a { display: inline-block; padding-block: .4rem; }
[hidden] { display: none !important; }
</style>
</head>
<body>
<main>
<h1>마우스와 키보드로 여는 메뉴</h1>
<nav aria-label="작업 둘러보기">
  <button type="button" id="toggle" aria-expanded="false"
    aria-controls="works" hidden>작업 목록</button>
  <ul id="works">
    <li><a href="#paper">종이 작업</a></li>
    <li><a href="#web">웹 작업</a></li>
  </ul>
</nav>
<section id="paper"><h2>종이 작업</h2><p>가상의 작품 목록이다.</p></section>
<section id="web"><h2>웹 작업</h2><p>가상의 작품 목록이다.</p></section>
</main>
<script>
const nav = document.querySelector("nav");
const button = document.querySelector("#toggle");
const list = document.querySelector("#works");
function setOpen(open) {
  button.setAttribute("aria-expanded", String(open));
  list.hidden = !open;
}
button.addEventListener("click", () => {
  setOpen(button.getAttribute("aria-expanded") !== "true");
});
nav.addEventListener("keydown", event => {
  if (event.key === "Escape" && !list.hidden) {
    setOpen(false);
    button.focus();
    event.preventDefault();
  }
});
nav.addEventListener("focusout", event => {
  if (event.relatedTarget && !nav.contains(event.relatedTarget)) setOpen(false);
});
document.addEventListener("click", event => {
  if (!nav.contains(event.target)) setOpen(false);
});
setOpen(false);
button.hidden = false;
</script>
</body>
</html>

마우스로 올려놓기만 해서는 열리지 않는다. 클릭이나 터치로 버튼을 누르거나 키보드로 조작한다. 웹 브라우저 설정에 따라 하이퍼링크로 Tab 이동을 켜야 할 수 있다. 시맨틱 HTML을 바탕으로 만들되 실제 적용 전에는 화면 낭독기에서도 확인한다. 메뉴가 필요 없을 만큼 항목이 적다면 접지 않아도 되는 메뉴가 더 편할 수 있다.

참고

#HTML #JavaScript #접근성

검색