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

이 튜토리얼에서는 웹사이트의 접근 가능한 기본 탐색을 빌드하는 방법을 설명합니다. 시맨틱 HTML, 접근성, ARIA 속성을 사용하면 이득보다 해가 될 수 있는 경우를 알아봅니다.

Manuel Matuzović
Manuel Matuzović

스타일, 기능, 기본 마크업 및 시맨틱 정보 측면에서 웹사이트의 기본 탐색을 만드는 방법은 다양합니다. 구현이 너무 간소하면 대부분의 사용자에게 작동하지만 사용자 환경(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(상태)는 컨테이너 또는 관련 요소 집합 내에서 현재 항목을 나타내는 요소를 나타냅니다. 페이지로 나누기 링크 집합 내의 링크를 나타내는 데 사용되는 페이지 토큰으로, 링크의 시각적 스타일은 현재 표시되는 페이지를 나타내도록 지정됩니다. [Accessible Rich Internet Applications(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에서 활성 페이지 강조 표시를 확인합니다.

항목 수 알림

시각 장애가 없는 사용자는 탐색 메뉴를 보고 링크가 4개만 포함되어 있음을 알 수 있습니다. 시각 장애가 있는 스크린 리더 사용자는 이 정보를 빠르게 얻을 수 없습니다. 전체 링크 목록을 살펴봐야 할 수도 있습니다. 이 예와 같이 목록이 짧은 경우에는 문제가 되지 않을 수 있지만 링크가 40개 포함된 경우에는 번거로울 수 있습니다. 스크린 리더 사용자가 탐색에 링크가 많이 포함되어 있음을 미리 알고 있다면 사이트 검색과 같이 더 효율적인 다른 탐색 방법을 사용하기 위해 결정할 수 있습니다.
항목 수를 미리 알리는 좋은 방법은 각 링크를 목록 항목(<li>)으로 래핑하고 순서 없는 목록(<ul>)에 중첩하는 것입니다.

<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를 누르면 로터로 페이지의 모든 랜드마크를 표시할 수 있습니다.

배너, 탐색, 기본, 콘텐츠 정보의 4가지 랜드마크 목록
페이지의 모든 랜드마크를 나열하는 VoiceOver의 로터

이 목록에는 4개의 랜드마크가 표시됩니다. <header> 요소인 배너, <nav>탐색, <main> 요소인 기본, <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>

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

명소
'배너', '기본 탐색', '기본', '페이지 탐색', '페이지 탐색 선택', '콘텐츠 정보' 랜드마크를 나열하는 음성 해설
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-label에서 제공하는 텍스트 라벨이 이미 있으므로 aria-hidden를 사용하여 보조 기술에서 <svg>를 숨깁니다.
  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를 사용하는 것이 중요합니다. 키보드 또는 스크린 리더 사용자가 버튼을 클릭한 후 키를 누르면 목록의 첫 번째 항목에 포커스가 설정될 것으로 예상합니다. 버튼이 목록 뒤에 있으면 그렇지 않습니다.

그런 다음 버튼의 기본 스타일을 재설정하고 좁은 뷰포트에서만 표시되도록 합니다.

@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에서는 작동하지 않습니다. display 속성이 애니메이션 가능하지 않기 때문입니다.

다음 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에서 포커스가 지정된 링크 주위에 파란색 2px 윤곽선이 표시됩니다.

원하는 색상으로 자체 스타일을 제공하여 이를 개선할 수 있습니다. :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의 브라우저 지원

브라우저 지원

  • Chrome: 86
  • Edge: 86.
  • Firefox: 85.
  • Safari: 15.4

소스

안에 간격이 있는 어두운 2px 윤곽선이 선명하게 보입니다.

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

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

축하합니다. 점진적으로 개선되고 의미가 풍부하며 액세스가 쉽고 모바일 친화적인 기본 탐색을 빌드했습니다.

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

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

이 도움말의 시작 부분에서 솔루션이 '너무 단순하지도 않고 너무 복잡하지도 않아야' 한다고 언급했습니다. 이제 그 목표를 달성했습니다. 하지만 탐색을 오버엔지니어링할 수는 있습니다.

탐색과 메뉴 사이에는 분명한 차이가 있습니다. 탐색은 관련 문서를 탐색하기 위한 링크 모음입니다. 메뉴는 문서에서 실행할 작업 모음입니다. 이러한 작업이 중복될 때도 있습니다. 모달 창 열기와 같은 작업을 실행하는 버튼이 포함된 탐색이 있거나 한 작업이 도움말 페이지와 같이 다른 페이지로 이동하는 메뉴가 있을 수 있습니다. 이 경우 ARIA 역할을 혼합하지 말고 구성요소의 기본 목적을 파악한 후 그에 따라 마크업과 역할을 선택하는 것이 중요합니다.

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

탐색 역할

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

탐색(역할) WAI-ARIA 1.1

메뉴 역할

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

메뉴(역할) WAI-ARIA 1.1

메뉴 바 역할

일반적으로 계속 표시되고 일반적으로 가로로 표시되는 메뉴 프레젠테이션입니다. menubar 역할은 Windows, Mac, Gnome 데스크톱 애플리케이션에 있는 메뉴 바와 유사한 메뉴 바를 만드는 데 사용됩니다. 메뉴 바는 자주 사용하는 일관된 명령어 세트를 만드는 데 사용됩니다. 개발자는 메뉴 바 상호작용이 데스크톱 그래픽 사용자 인터페이스의 일반적인 메뉴 바 상호작용과 유사한지 확인해야 합니다.

menubar(역할) WAI-ARIA 1.1

Menuitem 역할

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

menuitem (역할) WAI-ARIA 1.1

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

메뉴는 언제 적절한가요?

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

<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) 또는 웹 앱도 포함됩니다. 기본 스택은 중요하지 않습니다. 데스크톱 애플리케이션과 매우 유사한 항목을 빌드하는 것이 아니라면 메뉴 역할을 사용하지 마세요.

추가 리소스

히어로 이미지 제공: 믹 하우프트