웹사이트의 기본 탐색 메뉴 빌드하기

이 튜토리얼에서는 웹사이트의 액세스 가능한 기본 탐색을 빌드하는 방법을 설명합니다. 시맨틱 HTML, 접근성, 그리고 ARIA 속성 사용이 어떻게 장점보다 해가 되는지에 대해 학습합니다.

마누엘 마투조비치
마누엘 마투조비치

웹사이트의 기본 탐색을 빌드하는 데는 스타일, 기능, 기본 마크업 및 의미 정보 등의 여러 가지 방법이 있습니다. 구현이 너무 단순하면 대부분의 사용자에게 적합하지만 사용자 환경 (UX)이 좋지 않을 수 있습니다. 과도하게 엔지니어링되면 사용자에게 혼란을 주거나 액세스하는 데 방해가 될 수 있습니다.

대부분의 웹사이트는 너무 간단하지도 복잡하지 않은 웹사이트를 만드는 것이 좋습니다.

레이어별 건물

이 튜토리얼에서는 기본 설정으로 시작하여 대부분의 사용자를 만족시키기에 충분한 정보와 스타일, 기능을 제공할 때까지 레이어별로 지형지물을 추가합니다. 이를 위해서는 가장 기본적이고 강력한 솔루션부터 시작하여 점진적으로 기능 레이어를 추가하는 점진적 개선 원칙을 사용해야 합니다. 어떤 이유로든 한 레이어가 작동하지 않아도 탐색은 기본 레이어로 적절하게 대체되므로 계속 작동합니다.

기본 구조

기본 탐색에는 <a> 요소와 몇 줄의 CSS가 있어야 링크의 기본 스타일과 레이아웃을 개선할 수 있습니다.

<a href="/home">Home</a>
<a href="/about-us">About us</a>
<a href="/pricing">Pricing</a>
<a href="/contact">Contact</a>
/* Define variables for your colors */
:root {
  --color-shades-dark: rgb(25, 25, 25);
}

/* Use the alternative box model
Details: <https://web.dev/learn/css/box-model/> */
*{
  box-sizing: border-box;
}

/* Basic font styling */
body {
  font-family: Segoe UI, system-ui, -apple-system, sans-serif;
  font-size: 1.6rem;
}

/* Link styling */
a {
  --text-color: var(--color-shades-dark);
  border-block-end: 3px solid var(--border-color, transparent);
  color: var(--text-color);
  display: inline-block;
  margin-block-end: 0.5rem; /* See note at the bottom of this chapter */
  margin-inline-end: 0.5rem;
  padding: 0.1rem;
  text-decoration: none;
}

/* Change the border-color on :hover and :focus */
a:where(:hover, :focus) {
  --border-color: var(--text-color);
}
CodePen에서 1단계: 기본 HTML 및 CSS 보기

이 방법은 사이트에 액세스하는 방법과 상관없이 대부분의 사용자에게 적합합니다. 마우스, 키보드, 터치 기기 또는 스크린 리더로 탐색에 액세스할 수 있지만 개선의 여지가 있습니다. 추가 기능과 정보를 사용하여 이 기본 패턴을 확장하여 환경을 개선할 수 있습니다.

방법은 다음과 같습니다.

  • 활성 페이지를 강조표시합니다.
  • 스크린 리더 사용자에게 항목 수를 알립니다.
  • 랜드마크를 추가하고 스크린 리더 사용자가 바로가기를 사용하여 직접 탐색에 액세스하도록 허용합니다.
  • 좁은 표시 영역에서는 탐색을 숨깁니다.
  • 포커스 스타일 지정을 개선합니다.

활성 페이지 강조표시

활성 페이지를 강조표시하려면 해당 링크에 수업을 추가하면 됩니다.

<a href="/about-us" class="active-page">About us</a>

이 접근 방식의 문제는 링크가 시각적으로만 활성 상태인 정보를 전달한다는 것입니다. 블라인드 스크린 리더 사용자는 활성 페이지와 다른 페이지를 구분할 수 없습니다. 다행히도 Accessible Rich Internet Applications (ARIA) 표준은 이러한 정보를 의미론적으로 전달하는 방법도 제공합니다. 클래스 대신 aria-current="page" 속성 및 값을 사용하세요.

aria-current (상태)는 컨테이너 또는 관련 요소 집합 내의 현재 항목을 나타내는 요소를 나타냅니다. 페이지로 나누기 링크 집합 내에서 링크를 나타내는 데 사용되는 페이지 토큰입니다. 링크는 현재 표시된 페이지를 나타내도록 시각적으로 스타일이 지정됩니다. [액세스 가능한 리치 인터넷 애플리케이션 (WAI-ARIA) 1.1](https://www.w3.org/TR/wai-aria/#aria-current)

추가 속성을 사용하면 이제 스크린 리더가 '링크, 회사 소개' 대신 '현재 페이지, 링크, 회사 소개'와 같은 내용을 알려줍니다.

<a href="/about-us" aria-current="page" class="active-page">About us</a>

편리한 부작용은 속성을 사용하여 CSS에서 활성 링크를 선택할 수 있으므로 active-page 클래스가 더 이상 사용되지 않습니다.

<a href="/home">Home</a>
<a href="/about-us" aria-current="page">About us</a>
<a href="/pricing">Pricing</a>
<a href="/contact">Contact</a>
/* Change border-color and color for the active page */
[aria-current="page"] {
  --border-color: var(--color-highlight);
  --text-color: var(--color-highlight);
}
2단계: CodePen의 활성 페이지 강조표시를 확인합니다.

항목 수 알림

일반 사용자는 내비게이션을 살펴봄으로써 네 개의 링크만 포함되어 있음을 알 수 있습니다. 블라인드 스크린 리더 사용자는 이 정보를 빠르게 얻을 수 없습니다. 전체 링크 목록을 일일이 살펴보아야 할 수도 있습니다. 이 예와 같이 목록이 짧으면 문제가 되지 않을 수 있지만 링크가 40개 포함되어 있으면 이 작업이 번거로울 수 있습니다. 스크린 리더 사용자가 탐색에 많은 링크가 포함되어 있음을 미리 알고 있는 경우 사이트 검색과 같은 보다 효율적인 다른 탐색 방법을 사용할 수 있습니다.
항목 수를 미리 전달하는 좋은 방법은 순서가 지정되지 않은 목록 (<ul>)에 중첩되어 있는 목록 항목 (<li>)의 각 링크를 래핑하는 것입니다.

<ul>
  <li>
     <a href="/home">Home</a>
  </li>
  <li>
    <a href="/about-us" aria-current="page">About us</a>
  </li>
  <li>
    <a href="/pricing">Pricing</a>
  </li>
  <li>
    <a href="/contact">Contact</a>
  </li>
</ul>

스크린 리더 사용자가 목록을 찾으면 소프트웨어에서 '목록, 항목 4개'와 같은 메시지를 알려줍니다.

다음은 Windows에서 스크린 리더 NVDA와 함께 사용되는 탐색의 데모입니다.

이제 이전처럼 보이도록 스타일을 조정해야 합니다.

/* Remove the default list styling and create a flexible layout for the list */
ul {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Basic link styling */
a {
  --text-color: var(--color-shades-dark);

  border-block-end: 3px solid var(--border-color, transparent);
  color: var(--text-color);
  padding: 0.1rem;
  text-decoration: none;
}

목록을 사용하면 스크린 리더 사용자에게 다음과 같은 여러 이점이 있습니다.

  • 항목과 상호작용하기 전에 총 항목 수를 확인할 수 있습니다.
  • 단축키를 사용하여 목록 항목에서 목록 항목으로 이동할 수 있습니다.
  • 단축키를 사용하여 목록 사이를 이동할 수 있습니다.
  • 스크린 리더가 현재 항목의 색인 (예: '목록 항목, 4개 중 2개')을 알려줄 수 있습니다.

또한, 페이지가 CSS 없이 표시되는 경우 목록에는 링크 쌓기가 아닌 일관된 항목 그룹으로 링크가 표시됩니다.

Safari에서 VoiceOver를 사용할 때 주목할 만한 점은 list-style: none를 설정하면 이러한 장점을 모두 잃게 된다는 점입니다. 처음부터 그렇게 설계되어 있습니다. WebKit팀은 목록이 목록과 보이지 않을 때 목록 의미 체계를 삭제하기로 했습니다. 탐색의 복잡성에 따라 이것이 문제가 될 수도 있고 문제가 되지 않을 수도 있습니다. 탐색 기능을 계속 사용할 수 있으며 Safari의 VoiceOver에만 영향을 미칩니다. Chrome 또는 Firefox를 사용하는 VoiceOver는 항목 수뿐만 아니라 NVDA와 같은 다른 스크린 리더도 알려줍니다. 반면에 시맨틱 정보는 상황에 따라 아주 유용할 수 있습니다. 그렇게 하려면 실제 스크린 리더 사용자를 대상으로 탐색을 테스트하고 의견을 얻어야 합니다. Safari에서 VoiceOver가 다른 모든 스크린 리더처럼 작동하도록 하려면 <ul>에서 ARIA 목록 역할을 명시적으로 설정하여 문제를 해결할 수 있습니다. 이렇게 하면 목록 스타일을 삭제하기 전의 상태로 동작이 되돌아갑니다. 시각적으로는 목록이 여전히 동일하게 보입니다.

<ul role="list">
  <li>
     <a href="/home">Home</a>
  </li>
  ...
</ul>
3단계: CodePen의 항목 수 공지를 참조하세요.

랜드마크 추가

약간의 노력으로 스크린 리더 사용자를 위해 큰 개선이 이루어졌지만 한 가지 더 할 수 있는 작업이 더 있습니다. 탐색은 의미론적으로는 여전히 링크 목록으로 이루어져 있으며 이 특정 목록이 웹사이트의 기본 탐색 메뉴인지는 알 수 없습니다. <nav> 요소에 <ul>를 래핑하여 이 일반 목록을 탐색 목록으로 변환할 수 있습니다.

<nav> 요소를 사용하면 여러 가지 이점이 있습니다. 특히 스크린 리더는 사용자가 상호작용할 때 '탐색'과 같은 내용을 알리고 페이지에 랜드마크를 추가합니다. 랜드마크는 <header>, <footer> 또는 <main>와 같이 페이지에서 스크린 리더가 이동할 수 있는 특수 영역입니다. 페이지에 랜드마크를 배치하면 스크린 리더 사용자가 페이지의 나머지 부분과 상호작용할 필요 없이 페이지의 중요한 영역에 직접 액세스할 수 있으므로 유용합니다. 예를 들어 NVDA에서 D 키를 눌러 랜드마크에서 랜드마크로 이동할 수 있습니다. 보이스오버에서 VO + U를 누르면 로터를 사용하여 페이지의 모든 랜드마크를 나열할 수 있습니다.

네 가지 랜드마크(배너, 탐색, 기본, 콘텐츠 정보)로 구성된 목록입니다.
페이지의 모든 랜드마크를 나열하는 VoiceOver의 로터입니다.

이 목록에는 4개의 랜드마크가 표시됩니다. banner<header> 요소, navigation<nav>, main<main> 요소, content information<footer>입니다. 이 목록은 너무 길면 안 됩니다. 사이트 검색, 지역 탐색 또는 페이지로 나누기와 같이 UI의 중요한 부분만 랜드마크로 표시하는 것이 좋습니다.

사이트 전체 탐색, 페이지의 로컬 탐색, 단일 페이지에 페이지로 나누기가 있는 경우 <nav> 요소 3개도 있을 수 있습니다. 괜찮습니다. 하지만 이제 세 개의 탐색 랜드마크가 있으며 의미상 모두 동일하게 보입니다. 페이지의 구조를 잘 알지 못하면 구분하기가 어렵습니다.

모두 &#39;내비게이션&#39;이라고 표시된 3개의 랜드마크를 보여주는 이미지입니다.
라벨이 지정되지 않은 세 개의 탐색 랜드마크가 나열된 VoiceOver의 로터

구분하기 쉽게 만들려면 aria-labelledby 또는 aria-label를 사용하여 라벨을 지정해야 합니다.

<nav aria-label="Main">
    <ul>
      <li>
         <a href="/home">Home</a>
      </li>
      ...
  </ul>
</nav>
...
<nav aria-label="Select page">
    <ul>
      <li>
         <a href="/page-1">1</a>
      </li>
      ...
    </ul>
</nav>

선택한 라벨이 이미 페이지 어딘가에 있다면 대신 aria-labelledby를 사용하고 id 속성을 사용하여 기존 라벨을 참조할 수 있습니다.

<nav aria-labelledby="pagination_heading">
  <h2 id="pagination_heading">Select a page</h2>
  <ul>
    <li>
       <a href="/page-1">1</a>
    </li>
    ...
  </ul>
</nav>

간결한 라벨로 충분합니다. 너무 장황하지 마세요. '탐색' 또는 '메뉴'와 같은 표현식은 스크린 리더에서 이미 사용자에게 제공하므로 생략합니다.

명소
랜드마크 '배너', '기본 탐색', '기본', '페이지 탐색', '페이지 탐색 선택', '콘텐츠 정보'를 나열한 VoiceOver
4단계: CodePen에 랜드마크 추가를 확인합니다.

좁은 표시 영역에서 탐색 숨기기

개인적으로 저는 좁은 뷰포트에서 기본 탐색을 숨기는 것을 좋아하지는 않지만 링크 목록이 너무 길어지면 우회할 방법이 없습니다. 이 경우 목록 대신 '메뉴', 햄버거 아이콘 또는 두 가지 조합의 버튼이 표시됩니다. 버튼을 클릭하면 목록이 표시되거나 숨겨집니다. 기본적인 JavaScript와 CSS를 알고 있다면 할 수 있는 일이지만, UX 및 접근성 측면에서 몇 가지를 처리해야 합니다.

  • 접근 가능한 방식으로 목록을 숨겨야 합니다.
  • 키보드로 탐색이 가능해야 합니다.
  • 탐색은 표시 여부를 전달해야 합니다.

버거 버튼 추가

점진적 개선 원칙을 따르고 있으므로 JavaScript가 사용 중지되어 있어도 탐색이 계속 작동하고 의미가 있는지 확인할 수 있습니다.
탐색에 가장 먼저 필요한 것은 햄버거 버튼입니다. 템플릿 요소의 HTML로 템플릿을 만들고 JavaScript로 클론하여 탐색에 추가합니다.

버거 버튼이 표시된 페이지
결과: 좁은 표시 영역에는 링크 대신 버거 버튼이 탐색에 표시됩니다.
<nav id="mainnav">
  ...
</nav>

<template id="burger-template">
  <button type="button" aria-expanded="false" aria-label="Menu" aria-controls="mainnav">
    <svg width="24" height="24" aria-hidden="true">
      <path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z">
    </svg>
  </button>
</template>
  1. aria-expanded 속성은 버튼으로 제어하는 요소의 확장 여부를 스크린 리더 소프트웨어에 알려줍니다.
  2. aria-label는 버튼에 버거 아이콘 대신 텍스트 대체인 소위 접근성 있는 이름을 지정합니다.
  3. aria-hidden를 사용하여 보조 기술에서 <svg>을(를) 숨깁니다. 이미 aria-label에서 제공한 텍스트 라벨이 있기 때문입니다.
  4. aria-controls는 보조 기술에 버튼이 제어하는 요소 (예: JAWS)를 지원하는 것을 알려줍니다.
const nav = document.querySelector('#mainnav')
const list = nav.querySelector('ul');
const burgerClone = document.querySelector('#burger-template').content.cloneNode(true);
const button = burgerClone.querySelector('button');

// Toggle aria-expanded attribute
button.addEventListener('click', e => {
  // aria-expanded="true" signals that the menu is currently open
  const isOpen = button.getAttribute('aria-expanded') === "true"
  button.setAttribute('aria-expanded', !isOpen);
});

// Hide list on keydown Escape
nav.addEventListener('keyup', e => {
  if (e.code === 'Escape') {
    button.setAttribute('aria-expanded', false);
  }
});

// Add the button to the page
nav.insertBefore(burgerClone, list);
  1. 사용자는 Esc 키를 눌러 언제든지 탐색을 닫을 수 있어 편리합니다.
  2. 버튼이 탐색의 첫 번째 요소여야 하므로 appendChild 대신 insertBefore를 사용하는 것이 중요합니다. 키보드 또는 스크린 리더 사용자가 버튼을 클릭한 후 Tab 키를 누르면 목록의 첫 번째 항목에 포커스가 있을 것으로 예상합니다. 이 버튼이 목록 다음에 오면 그렇지 않습니다.

그런 다음 버튼의 기본 스타일을 재설정하고 좁은 표시 영역에만 표시되는지 확인합니다.

@media (min-width: 48em) {
  nav {
    --nav-button-display: none;
  }
}

/* Reset button styling */
button {
  all: unset;
  display: var(--nav-button-display, flex);
}
5단계: CodePen에서 버거 버튼 추가를 참조하세요.

목록 숨기기

목록을 숨기기 전에 레이아웃이 좁은 표시 영역에 맞게 최적화되고 큰 화면에서는 보기 좋도록 탐색 및 목록의 위치와 스타일을 지정합니다.
먼저 페이지의 자연스러운 흐름에서 <nav>를 삭제하고 표시 영역의 상단 끝에 배치합니다.

@media (min-width: 48em) {
  nav {
    --nav-button-display: none;
    --nav-position: static;
  }
}

nav {
  position: var(--nav-position, fixed);
  inset-block-start: 1rem;
  inset-inline-end: 1rem;
}

이제 새로운 맞춤 속성 (—-nav-list-layout)를 추가하여 좁은 표시 영역의 레이아웃을 변경합니다. 레이아웃은 기본적으로 열이며 큰 화면에서는 행으로 전환됩니다.

@media (min-width: 48em) {
  nav {
    --nav-button-display: none;
    --nav-position: static;
  }

  ul {
    --nav-list-layout: row;
  }
}

ul {
  display: flex;
  flex-direction: var(--nav-list-layout, column);
  flex-wrap: wrap;
  gap: 1rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

좁은 표시 영역에서 탐색은 다음과 같이 표시됩니다.

탐색 목록과 버거 버튼을 보여주는 페이지
햄버거 버튼과 목록은 모두 표시 영역의 상단 모서리에 배치됩니다.

목록에 분명히 몇 가지 CSS가 필요합니다. 상단 모서리로 이동하여 전체 화면을 세로로 채우고 background-colorbox-shadow를 적용합니다.

@media (min-width: 48em) {
  nav {
    --nav-button-display: none;
    --nav-position: static;
  }
  
  ul {
    --nav-list-layout: row;
    --nav-list-position: static;
    --nav-list-padding: 0;
    --nav-list-height: auto;
    --nav-list-width: 100%;
    --nav-list-shadow: none;
  }
}

ul {
  background: rgb(255, 255, 255);
  box-shadow: var(--nav-list-shadow, -5px 0 11px 0 rgb(0 0 0 / 0.2));
  display: flex;
  flex-direction: var(--nav-list-layout, column);
  flex-wrap: wrap;
  gap: 1rem;
  height: var(--nav-list-height, 100vh);
  list-style: none;
  margin: 0;
  padding: var(--nav-list-padding, 2rem);
  position: var(--nav-list-position, fixed);
  inset-block-start: 0; /* Logical property. Equivalent to top: 0; */
  inset-inline-end: 0; /* Logical property. Equivalent to right: 0; */
  width: var(--nav-list-width, min(22rem, 100vw));
}

button {
  all: unset;
  display: var(--nav-button-display, flex);
  position: relative;
  z-index: 1;
}

좁은 표시 영역에서는 목록이 다음과 같이 표시되며 단순한 목록보다 사이드바에 더 가깝습니다.

탐색 목록이 열립니다.

마지막으로 목록을 숨기고 사용자가 버튼을 한 번 클릭할 때만 표시하고 다시 클릭할 때만 숨깁니다. 탐색 메뉴를 숨기면 중요한 랜드마크가 숨겨지기 때문에 전체 탐색이 아닌 목록만 숨기는 것이 중요합니다.

앞에서 aria-expanded 속성의 값을 전환하기 위해 버튼에 클릭 이벤트를 추가했습니다. 이 정보를 CSS에서 목록을 표시하고 숨기기 위한 조건으로 사용할 수 있습니다.

@media (min-width: 48em) {
  ul {
    --nav-list-visibility: visible;
  }
}

ul {
  visibility: var(--nav-list-visibility, visible);
}

/* Hide the list on narrow viewports, if it comes after an element with
   aria-expanded set to "false". */
[aria-expanded="false"] + ul {
  visibility: var(--nav-list-visibility, hidden);
}

목록을 숨기려면 opacity: 0 또는 translateX(100%) 대신 visibility: hidden 또는 display: none와 같은 속성 선언을 사용하는 것이 중요합니다. 이러한 속성은 탐색이 숨겨져 있을 때 링크에 포커스를 둘 수 없도록 합니다. opacity 또는 translate를 사용하면 콘텐츠가 시각적으로 삭제되므로 링크는 보이지 않지만 키보드를 사용하여 여전히 액세스할 수 있어 혼란과 불편을 초래할 수 있습니다. visibility 또는 display를 사용하면 객체가 시각적으로 숨겨지고 액세스할 수 없게 되므로 모든 사용자가 볼 수 없도록 숨겨집니다.

6단계: 목록 숨기기 보기

목록에 애니메이션 적용

display: none;보다 visibility: hidden;를 사용하는 이유가 궁금하다면 공개 상태를 애니메이션으로 보여줄 수 있기 때문입니다. hiddenvisible의 두 가지 상태만 있지만 transform 또는 opacity와 같은 다른 속성과 결합하여 슬라이드 또는 페이드 인 효과를 만들 수 있습니다. 이 방법은 display: none이 작동하지 않습니다. 디스플레이 속성이 애니메이션화할 수 없기 때문입니다.

다음 CSS는 opacity를 전환하여 페이드 인 및 페이드 아웃 효과를 만듭니다.

ul {
  transition: opacity 0.6s linear, visibility 0.3s linear;
  visibility: var(--nav-list-visibility, visible);
}

[aria-expanded="false"] + ul {
  opacity: 0;
  visibility: var(--nav-list-visibility, hidden);
}

대신 모션을 애니메이션으로 처리하려면 transition 속성을 prefers-reduced-motion 미디어 쿼리에 래핑하는 것이 좋습니다. 애니메이션이 일부 사용자에게 메스꺼움, 현기증, 두통을 유발할 수 있기 때문입니다.

ul {
  visibility: var(--nav-list-visibility, visible);
}

@media (prefers-reduced-motion: no-preference) {
  ul {
    transition: transform 0.6s cubic-bezier(.68,-0.55,.27,1.55), visibility 0.3s linear;
  }
}

[aria-expanded="false"] + ul {
  transform: var(--nav-list-transform, translateX(100%));
  visibility: var(--nav-list-visibility, hidden);
}

이렇게 하면 움직임을 줄여주는 것을 선호하지 않는 사람만 애니메이션을 볼 수 있습니다.

7단계: CodePen에서 목록에 애니메이션 적용을 봅니다.

포커스 스타일 지정 개선

키보드 사용자는 페이지 방향과 탐색을 위해 요소의 포커스 스타일을 사용합니다. 기본 포커스 스타일이 포커스 스타일이 없는 것보다 낫지만 (outline: none를 설정하는 경우 발생함), 더 명확하게 표시되는 맞춤 포커스 스타일을 사용하면 사용자 환경이 개선됩니다.

Chrome 103에서 링크의 기본 포커스 스타일이 다음과 같이 표시됩니다.

Chrome 103에서 포커스가 맞춰진 링크 주변의 파란색 2픽셀 윤곽선

고유의 색상으로 고유한 스타일을 제공하여 이를 개선할 수 있습니다. :focus 대신 :focus-visible를 사용하면 브라우저에서 포커스 스타일을 표시하기에 적절한 시점을 결정하게 됩니다. :focus 스타일은 필요 여부와 관계없이 모든 사용자, 마우스, 키보드, 터치 사용자에게 표시됩니다. :focus-visible를 사용하면 브라우저가 내부 휴리스틱을 사용하여 키보드 사용자에게만 표시할지 아니면 모든 사용자에게 표시할지 결정합니다.

/* Remove the default :focus outline */
*:focus {
  outline: none;
}

/* Show a custom outline on :focus-visible */
*:focus-visible {
  outline: 2px solid var(--color-shades-dark);
  outline-offset: 4px;
}

:focus-visible 브라우저 지원

브라우저 지원

  • 86
  • 86
  • 85
  • 15.4

소스

선명하게 보이는 어두운 2픽셀 윤곽선(내부 간격 포함)

항목에 포커스가 있을 때 항목을 강조 표시하는 방법에는 여러 가지가 있습니다. outline 속성은 레이아웃을 손상시키지 않으며(border에서 발생할 수 있음) Windows의 고대비 모드에서 잘 작동하므로 이 속성을 사용하는 것이 좋습니다. 제대로 작동하지 않는 속성은 background-color 또는 box-shadow입니다. 맞춤 대비 설정으로 전혀 표시되지 않을 수 있기 때문입니다.

어두운 배경에 초점이 보라색으로 강조 표시된 사이트
8단계: CodePen에서 포커스 스타일 개선을 확인합니다.

수고하셨습니다 점진적으로 개선되고 의미론적으로 풍부하며 접근성과 모바일 친화적인 기본 탐색을 빌드했습니다.

항상 다음과 같이 개선할 수 있는 부분이 있습니다.

  • 탐색 내부에서 포커스를 트래핑하거나 좁은 표시 영역에서 페이지의 나머지 부분을 무효화하는 방법을 고려해 보세요.
  • 페이지 상단에 건너뛰기 링크를 추가하여 키보드 사용자가 탐색을 건너뛸 수 있도록 할 수 있습니다.

이 기사가 어떻게 시작되었는지 기억하시겠지만, 솔루션이 "너무 간단하거나 너무 복잡하지 않아야 함"을 목표로 삼고 있으시다면, 그것이 바로 지금 여기에 있습니다. 하지만 탐색을 오버엔지니어링할 수도 있습니다.

탐색과 메뉴에는 분명한 차이가 있습니다. 탐색은 관련 문서를 탐색하기 위한 링크 모음입니다. 메뉴는 문서에서 실행할 작업의 모음입니다. 이러한 태스크가 겹치는 경우도 있습니다. 작업을 실행하는 버튼(예: 모달 창 열기)을 포함하는 탐색이 있거나 한 작업이 도움말 페이지와 같이 다른 페이지로 이동하는 메뉴가 있을 수 있습니다. 이 경우 ARIA 역할을 섞지 말고 구성 요소의 주요 목적을 파악하고 그에 따라 마크업과 역할을 선택해야 합니다.

<nav> 요소에는 탐색이라는 암시적 ARIA 역할이 있어 요소가 탐색임을 전달하기에 충분하지만 사이트에서 메뉴, 메뉴 바, 메뉴 항목도 사용하는 경우가 많습니다. Google에서는 이러한 용어를 서로 바꿔서 사용할 수 있으므로 스크린 리더 사용자의 경험을 개선하기 위해 이러한 용어를 결합하는 것이 합리적일 수 있습니다. 일반적으로 그렇지 않은 이유를 알아보기 전에 이러한 역할의 공식 정의를 살펴보겠습니다.

탐색 역할

문서나 관련 문서를 탐색하기 위한 탐색 요소 (일반적으로 링크) 모음입니다.

내비게이션 (역할) WAI-ARIA 1.1

메뉴 역할

메뉴는 사용자가 호출할 수 있는 일반적인 작업 또는 기능의 목록인 경우가 많습니다. 메뉴 역할은 메뉴 항목 목록이 데스크톱 애플리케이션의 메뉴와 유사한 방식으로 제공될 때 적합합니다.

메뉴 (역할) WAI-ARIA 1.1

메뉴 바 역할

일반적으로 계속 보이는 메뉴를 표시하고 일반적으로 가로로 표시됩니다. 메뉴 바 역할은 Windows, Mac, Gnome 데스크톱 애플리케이션에서 볼 수 있는 것과 유사한 메뉴 바를 만드는 데 사용됩니다. 메뉴 바는 자주 사용되는 명령어 집합을 만드는 데 사용됩니다. 작성자는 메뉴바 상호작용이 데스크톱 그래픽 사용자 인터페이스의 일반적인 메뉴바 상호작용과 유사한지 확인해야 합니다.

메뉴 바 (역할) WAI-ARIA 1.1

Menuitem 역할

메뉴 또는 메뉴 바에 포함된 선택사항 집합의 옵션입니다.

menuitem (역할) WAI-ARIA 1.1

사양은 매우 명확합니다. 문서 또는 관련 문서를 탐색하려면 탐색을 사용하고 데스크톱 애플리케이션의 메뉴와 유사한 작업 또는 기능 목록의 경우에만 메뉴를 사용하세요. 다음 Google 문서를 빌드하지 않는 경우 기본 탐색에 대한 메뉴 역할이 필요하지 않을 수 있습니다.

메뉴가 적절한 경우는 언제인가요?

메뉴 항목의 기본 용도는 탐색이 아니라 작업을 실행하는 것입니다. 데이터 목록이나 표가 있고 사용자가 목록의 각 항목에 대해 특정 작업을 수행할 수 있다고 가정해 보겠습니다. 각 행에 버튼을 추가하고 사용자가 버튼을 클릭할 때 액션을 표시할 수 있습니다.

<ul>
  <li>
    Product 1

    <button aria-expanded="false" aria-controls="options1">Edit</button>

    <div role="menu" id="options1">
      <button role="menuitem">
        Duplicate
      </button>
      <button role="menuitem">
        Delete
      </button>
      <button role="menuitem">
        Disable
      </button>
    </div>
  </li>
  <li>
    Product 2
    ...
  </li>
</ul>

메뉴 역할 사용의 의미

많은 문제가 발생할 수 있으므로 이러한 메뉴 역할을 현명하게 사용하는 것이 중요합니다.

메뉴에는 특정 DOM 구조가 필요합니다. menuitem은(는) menu의 직속 하위 항목이어야 합니다. 다음 코드는 시맨틱 동작을 중단할 수 있습니다.

 <!-- Wrong, don't do this -->
<ul role="menu">
  <li>
    <a href="#" role="menuitem">Item 1</a>
  </li>
</ul>

능숙한 사용자는 특정 단축키가 메뉴 및 메뉴 바에서 작동하기를 기대합니다. ARIA 작성 방법 가이드 (APG)에 따르면 여기에는 다음이 포함됩니다.

  • Enter스페이스바를 눌러 메뉴 항목을 선택합니다.
  • 모든 방향의 화살표 키를 사용하여 항목 간에 이동합니다.
  • HomeEnd 키를 각각 첫 번째 또는 마지막 항목으로 포커스를 이동합니다.
  • a-z: 입력한 문자로 시작하는 라벨이 있는 다음 메뉴 항목으로 포커스를 이동합니다.
  • Esc 키를 눌러 메뉴를 닫습니다.

스크린 리더가 메뉴를 감지하면 소프트웨어에서 자동으로 탐색 모드를 변경하여 앞서 언급한 단축키를 사용 설정할 수 있습니다. 스크린 리더에 익숙하지 않은 사용자는 이러한 단축키나 사용 방법을 모르기 때문에 메뉴를 사용하지 못할 수 있습니다.

이는 ShiftShift + Tab을 사용할 수 있을 것으로 예상하는 키보드 사용자에게도 마찬가지입니다.

메뉴와 메뉴 바를 만들 때는 고려해야 할 사항이 많습니다. 메뉴와 메뉴 모음을 처음부터 사용하는 것이 적절한지 여부입니다. 일반 웹사이트를 구축할 때는 목록과 링크가 포함된 탐색 요소만 있으면 됩니다. 여기에는 단일 페이지 애플리케이션 (SPA) 또는 웹 앱도 포함됩니다. 기본 스택은 중요하지 않습니다. 데스크톱 애플리케이션과 매우 유사한 것을 빌드하는 경우가 아니라면 메뉴 역할은 피하세요.

추가 리소스

히어로 이미지: Mick Haupt