Xây dựng bảng điều hướng chính cho trang web

Hướng dẫn này mô tả cách xây dựng thành phần điều hướng chính dễ truy cập trên trang web. Bạn sẽ tìm hiểu về HTML ngữ nghĩa, khả năng hỗ trợ tiếp cận cũng như việc sử dụng các thuộc tính ARIA đôi khi có thể gây hại hơn là có lợi.

Manuel Matuzović
Manuel Matuzović

Có nhiều cách để xây dựng phần điều hướng chính của trang web, xét về kiểu cách, chức năng, mã đánh dấu và thông tin ngữ nghĩa cơ bản. Nếu quá tối giản, phương thức triển khai sẽ phù hợp với hầu hết mọi người, nhưng trải nghiệm người dùng (UX) có thể không được tốt. Nếu được thiết kế quá mức, ứng dụng có thể gây nhầm lẫn cho người dùng hoặc thậm chí khiến họ không truy cập được.

Đối với hầu hết các trang web, bạn nên tạo một nội dung không quá đơn giản, cũng không quá phức tạp.

Xây dựng theo từng lớp

Trong hướng dẫn này, bạn bắt đầu với một thiết lập cơ bản và thêm các tính năng theo từng lớp đến mức bạn cung cấp vừa đủ thông tin, kiểu và chức năng để làm hài lòng hầu hết người dùng. Để đạt được mục tiêu đó, bạn nên sử dụng nguyên tắc nâng cao tăng dần, tức là nguyên tắc này nêu rõ rằng bạn bắt đầu với giải pháp cơ bản và mạnh mẽ nhất, đồng thời thêm dần các lớp chức năng. Nếu một lớp không thể hoạt động vì lý do nào đó, thành phần điều hướng vẫn sẽ hoạt động vì lớp này quay lại lớp bên dưới một cách linh hoạt.

Cấu trúc cơ bản

Để điều hướng cơ bản, bạn cần 2 thứ: phần tử <a> và vài dòng CSS để cải thiện kiểu và bố cục mặc định của các đường liên kết.

<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);
}
Xem Bước 1: HTML và CSS cơ bản" trên CodePen.

Cách này hiệu quả đối với hầu hết người dùng, bất kể họ truy cập trang web bằng cách nào. Bạn có thể sử dụng tính năng điều hướng bằng chuột, bàn phím, thiết bị cảm ứng hoặc trình đọc màn hình, nhưng có thể cải thiện thêm. Bạn có thể nâng cao trải nghiệm bằng cách mở rộng mẫu cơ bản này với chức năng và thông tin bổ sung.

Bạn có thể làm những việc sau:

  • Đánh dấu trang đang hoạt động.
  • Thông báo số lượng mục cho người dùng trình đọc màn hình.
  • Thêm điểm mốc và cho phép người dùng trình đọc màn hình truy cập trực tiếp vào tính năng điều hướng bằng cách sử dụng phím tắt.
  • Ẩn điều hướng trên khung nhìn hẹp.
  • Cải thiện định kiểu cho tiêu điểm.

Đánh dấu trang đang hoạt động

Để làm nổi bật trang đang hoạt động, bạn có thể thêm lớp học vào đường liên kết tương ứng.

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

Vấn đề của phương pháp này nằm ở chỗ nó truyền tải thông tin mà đường liên kết chỉ hoạt động một cách đơn thuần về mặt hình ảnh. Người dùng trình đọc màn hình khiếm thị không thể phân biệt giữa trang đang hoạt động với các trang khác. May mắn là tiêu chuẩn Ứng dụng Internet đa dạng thức có thể truy cập (ARIA) cũng cung cấp cho bạn cách truyền đạt thông tin này theo ngữ nghĩa. Sử dụng giá trị và thuộc tính aria-current=&quot;page&quot; thay vì một lớp.

aria-current (trạng thái) cho biết phần tử đại diện cho mục hiện tại trong một vùng chứa hoặc tập hợp các phần tử có liên quan. Mã thông báo trang được dùng để cho biết một liên kết trong một nhóm các liên kết phân trang, trong đó liên kết được tạo kiểu trực quan để thể hiện trang hiện đang hiển thị. [Ứng dụng Internet đa dạng thức có thể truy cập (WAI-ARIA) 1.1](https://www.w3.org/TR/wai-aria/#aria-current)

Với thuộc tính bổ sung này, trình đọc màn hình giờ đây sẽ thông báo những nội dung như "trang hiện tại, đường liên kết, Giới thiệu về chúng tôi" thay vì chỉ "liên kết, Giới thiệu về chúng tôi".

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

Một tác dụng phụ thuận tiện là bạn có thể sử dụng thuộc tính này để chọn đường liên kết đang hoạt động trong CSS, khiến lớp active-page trở nên lỗi thời.

<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);
}
Xem Bước 2: Đánh dấu trang đang hoạt động trên CodePen.

Thông báo số lượng mặt hàng

Bằng cách nhìn vào bảng điều hướng, người dùng nhìn thấy có thể biết rằng bảng điều hướng chỉ chứa bốn đường liên kết. Người dùng trình đọc màn hình khiếm thị không thể lấy thông tin này nhanh chóng. Các thẻ này có thể phải thao tác theo cách riêng của bạn thông qua toàn bộ danh sách các đường liên kết. Đây có thể không phải là vấn đề nếu danh sách ngắn như trong ví dụ này, nhưng nếu chứa 40 đường liên kết thì tác vụ này có thể rườm rà. Nếu người dùng trình đọc màn hình biết rõ rằng thành phần điều hướng chứa nhiều đường liên kết, họ có thể quyết định sử dụng một cách điều hướng khác hiệu quả hơn, chẳng hạn như tìm kiếm trên trang web.
Một cách hay để thông báo trước số lượng mục là gói từng đường liên kết trong một mục danh sách (<li>), lồng trong một danh sách không theo thứ tự (<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>

Khi người dùng trình đọc màn hình tìm thấy danh sách này, phần mềm của họ sẽ thông báo những nội dung như "list, 4 items" (danh sách, 4 mục).

Dưới đây là bản minh hoạ về thao tác điều hướng được sử dụng với NVDA trình đọc màn hình trên Windows.

Bây giờ, bạn phải điều chỉnh kiểu sao cho giống như trước đây.

/* 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;
}

Việc sử dụng danh sách có thể mang lại nhiều lợi ích cho người dùng trình đọc màn hình:

  • Họ có thể xem được tổng số mặt hàng trước khi tương tác với các mặt hàng đó.
  • Họ có thể sử dụng lối tắt để chuyển từ mục danh sách sang mục danh sách.
  • Họ có thể sử dụng lối tắt để chuyển từ danh sách này sang danh sách khác.
  • Trình đọc màn hình có thể thông báo chỉ mục của mục hiện tại (ví dụ: "mục danh sách, 2 trên 4").

Trên hết, nếu trang được trình bày mà không có CSS, thì danh sách sẽ hiển thị các đường liên kết dưới dạng một nhóm mục mạch lạc thay vì chỉ là một loạt đường liên kết.

Một chi tiết đáng chú ý về VoiceOver trong Safari là bạn sẽ mất tất cả những ưu điểm này khi đặt list-style: none. Điều này là do thiết kế. Nhóm WebKit quyết định xoá ngữ nghĩa của danh sách khi một danh sách trông không giống một danh sách. Tuỳ thuộc vào độ phức tạp của thao tác điều hướng, điều này có thể hoặc không phải là vấn đề. Một mặt, điều hướng vẫn có thể sử dụng được và nó chỉ ảnh hưởng đến VoiceOver trong Safari. VoiceOver với Chrome hoặc Firefox vẫn thông báo số lượng mục, cũng như các trình đọc màn hình khác, chẳng hạn như NVDA. Mặt khác, thông tin ngữ nghĩa có thể thực sự hữu ích trong một số trường hợp. Để đưa ra quyết định đó, bạn nên kiểm thử chức năng điều hướng với người dùng trình đọc màn hình thực tế và thu thập ý kiến phản hồi của họ. Nếu quyết định cần VoiceOver trong Safari để hoạt động như tất cả các trình đọc màn hình khác, bạn có thể giải quyết vấn đề này bằng cách đặt rõ ràng vai trò danh sách ARIA trên <ul>. Thao tác này sẽ chuyển hành vi về trạng thái trước khi bạn xoá kiểu danh sách. Về mặt trực quan, danh sách vẫn trông y như cũ.

<ul role="list">
  <li>
     <a href="/home">Home</a>
  </li>
  ...
</ul>
Xem Bước 3: Thông báo số lượng mục trên CodePen.

Thêm điểm mốc

Chỉ với một chút nỗ lực, bạn đã cải thiện hiệu quả cho người dùng trình đọc màn hình. Tuy nhiên, bạn vẫn có thể làm một việc nữa. Về mặt ngữ nghĩa, điều hướng vẫn chỉ là một danh sách các đường liên kết và khó để nói rằng danh sách cụ thể này là điều hướng chính trên trang web của bạn. Bạn có thể biến danh sách thông thường này thành danh sách điều hướng bằng cách gói <ul> trong phần tử <nav>.

Việc sử dụng phần tử <nav> có một số lợi ích. Đáng chú ý là trình đọc màn hình sẽ thông báo những nội dung như "điều hướng" khi người dùng tương tác với thao tác đó, đồng thời thêm một dấu mốc vào trang. Địa danh là các vùng đặc biệt trên trang, chẳng hạn như <header>, <footer> hoặc <main> mà trình đọc màn hình có thể chuyển tới đó. Các mốc trên trang có thể hữu ích, vì điểm mốc cho phép người dùng trình đọc màn hình truy cập trực tiếp vào các vùng quan trọng trên trang mà không phải tương tác với phần còn lại của trang. Ví dụ: bạn có thể chuyển từ điểm mốc sang điểm mốc bằng cách nhấn phím D trong NVDA. Trong Lồng tiếng, bạn có thể sử dụng rô-to để liệt kê tất cả các mốc trên trang bằng cách nhấn VO + U.

Danh sách 4 mốc: biểu ngữ, thanh điều hướng, chính, thông tin nội dung.
Rôto trong VoiceOver liệt kê tất cả các mốc trên một trang.

Trong danh sách này, bạn có thể thấy 4 mốc: banner là phần tử <header>, navigation<nav>, main là thành phần <main>thông tin nội dung<footer>. Danh sách này không nên quá dài. Bạn chỉ nên đánh dấu các phần quan trọng trên giao diện người dùng là mốc, chẳng hạn như tính năng tìm kiếm trên trang web, thanh điều hướng cục bộ hoặc tính năng phân trang.

Nếu có thành phần điều hướng trên toàn trang web, thành phần điều hướng cục bộ cho trang và chức năng phân trang trên một trang, thì bạn cũng có thể có 3 phần tử <nav>. Điều đó được, nhưng hiện có 3 mốc điều hướng và tất cả đều giống nhau về mặt ngữ nghĩa. Thật khó để phân biệt chúng với nhau, trừ khi bạn thực sự hiểu rõ cấu trúc của trang.

Hình ảnh cho thấy 3 địa danh đều có dòng chữ &quot;navigation&quot;.
Rôto trong VoiceOver liệt kê ba mốc điều hướng chưa được gắn nhãn.

Để dễ phân biệt các thẻ, bạn nên gắn nhãn chúng bằng cách sử dụng aria-labelledby hoặc 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>

Nếu nhãn bạn chọn đã tồn tại ở đâu đó trên trang, bạn có thể sử dụng aria-labelledby và tham chiếu đến nhãn hiện có bằng thuộc tính 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>

Nhãn ngắn gọn là đủ, đừng quá dài dòng. Bỏ qua các biểu thức như "navigation" hoặc "trình đơn" vì trình đọc màn hình đã cung cấp cho người dùng thông tin này.

Địa danh
VoiceOver liệt kê các điểm mốc "biểu ngữ", "điều hướng chính", "chính", "điều hướng trang", "chọn điều hướng trang" và "thông tin về nội dung".
Xem Bước 4: Thêm mốc trên CodePen.

Ẩn điều hướng trên khung nhìn hẹp

Cá nhân tôi không thích việc ẩn thanh điều hướng chính trên các khung nhìn hẹp, nhưng nếu danh sách các đường liên kết quá dài thì không có cách nào để xử lý. Nếu đúng như vậy, thay vì danh sách, người dùng sẽ thấy một nút có nhãn "Trình đơn" hoặc một biểu tượng bánh mì kẹp thịt hoặc một tổ hợp các loại. Thao tác nhấp vào nút này sẽ hiển thị và ẩn danh sách. Nếu bạn biết JavaScript và CSS cơ bản, đó là một tác vụ khả thi, nhưng có một số điều liên quan đến trải nghiệm người dùng và khả năng tiếp cận mà bạn phải quan tâm.

  • Bạn phải ẩn danh sách theo cách dễ tiếp cận.
  • Thành phần điều hướng phải truy cập được bằng bàn phím.
  • Thành phần điều hướng phải cho biết nó có hiển thị hay không.

Thêm nút bánh mì kẹp thịt

Vì đang tuân theo nguyên tắc nâng cao tăng dần, nên bạn muốn đảm bảo rằng thành phần điều hướng vẫn hoạt động và hợp lý ngay cả khi JavaScript tắt.
Điều đầu tiên bạn cần để điều hướng là một nút bánh mì kẹp thịt. Bạn tạo đoạn mã bằng HTML trong một phần tử mẫu, sao chép đoạn mã đó trong JavaScript rồi thêm vào thành phần điều hướng.

Một trang cho thấy nút bánh mì kẹp thịt.
Kết quả: Thay vì các đường liên kết, bảng điều hướng sẽ hiển thị nút bánh mì kẹp thịt trên khung nhìn hẹp.
<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. Thuộc tính aria-expanded cho phần mềm đọc màn hình biết phần tử mà nút điều khiển có được mở rộng hay không.
  2. aria-label đặt cho nút này một tên gọi dễ tiếp cận. Đây là một dạng văn bản thay thế cho biểu tượng bánh mì kẹp thịt.
  3. Bạn có thể ẩn <svg> khỏi công nghệ hỗ trợ bằng cách sử dụng aria-hidden vì nó đã có nhãn văn bản do aria-label cung cấp.
  4. aria-controls cho công nghệ hỗ trợ biết thuộc tính hỗ trợ (ví dụ như JAWS) nào mà nút điều khiển sẽ được điều khiển.
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. Người dùng có thể đóng ngăn điều hướng bất cứ khi nào họ muốn, chẳng hạn như bằng cách nhấn phím Escape.
  2. Bạn cần sử dụng insertBefore thay vì appendChild, vì nút này phải là thành phần đầu tiên trong thành phần điều hướng. Nếu người dùng bàn phím hoặc trình đọc màn hình nhấn Tab sau khi nhấp vào nút đó, họ muốn đặt tiêu điểm vào mục đầu tiên trong danh sách. Nếu nút này xuất hiện sau danh sách thì điều đó không đúng.

Tiếp theo, bạn đặt lại kiểu mặc định của nút và đảm bảo rằng nút chỉ hiển thị trên khung nhìn hẹp.

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

/* Reset button styling */
button {
  all: unset;
  display: var(--nav-button-display, flex);
}
Xem Bước 5: Thêm nút bánh mì kẹp thịt trên CodePen.

Đang ẩn danh sách

Trước khi bạn ẩn danh sách, hãy định vị và tạo kiểu cho phần điều hướng và danh sách để bố cục được tối ưu hoá cho các khung nhìn hẹp nhưng vẫn trông đẹp mắt trên màn hình lớn hơn.
Trước tiên, hãy xóa <nav> khỏi luồng tự nhiên của trang và đặt nút này ở góc trên cùng của khung nhìn.

@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;
}

Tiếp theo, hãy thay đổi bố cục trên khung nhìn hẹp bằng cách thêm thuộc tính tuỳ chỉnh mới (—-nav-list-layout). Bố cục là cột theo mặc định và chuyển sang hàng trên màn hình lớn hơn.

@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;
}

Cách điều hướng của bạn sẽ trông giống như sau trên khung nhìn hẹp.

Trang cho thấy danh sách điều hướng và nút bánh mì kẹp thịt.
Cả nút bánh mì kẹp thịt và danh sách đều được đặt ở góc trên cùng của khung nhìn.

Danh sách rõ ràng cần một số CSS. Chúng ta sẽ di chuyển thanh này lên góc trên cùng, làm cho nó lấp đầy toàn bộ màn hình theo chiều dọc, áp dụng 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;
}

Danh sách sẽ có dạng như dưới đây trên khung nhìn hẹp, giống với thanh bên hơn là danh sách đơn giản.

Danh sách điều hướng sẽ mở ra.

Cuối cùng, hãy ẩn danh sách, chỉ hiển thị danh sách khi người dùng nhấp vào nút một lần và ẩn danh sách khi họ nhấp lại. Bạn chỉ nên ẩn danh sách chứ không phải toàn bộ phần điều hướng vì việc ẩn phần điều hướng cũng có nghĩa là bạn phải ẩn một điểm mốc quan trọng.

Trước đó, bạn đã thêm một sự kiện nhấp chuột vào nút để bật/tắt giá trị của thuộc tính aria-expanded. Bạn có thể sử dụng thông tin đó làm điều kiện để hiển thị và ẩn danh sách trong 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);
}

Bạn cần sử dụng một phần khai báo thuộc tính như visibility: hidden hoặc display: none thay vì opacity: 0 hoặc translateX(100%) để ẩn danh sách. Những thuộc tính này đảm bảo rằng các đường liên kết không thể lấy tiêu điểm khi mục điều hướng bị ẩn. Việc sử dụng opacity hoặc translate sẽ xoá nội dung một cách trực quan, vì vậy, các đường liên kết sẽ không hiển thị nhưng vẫn truy cập được bằng bàn phím. Điều này gây nhầm lẫn và khó chịu. Việc sử dụng visibility hoặc display sẽ ẩn tiện ích một cách trực quan và khiến người dùng không thể truy cập được, do đó, thao tác này sẽ ẩn đối với tất cả người dùng.

Xem Bước 6: Ẩn danh sách.

Tạo ảnh động cho danh sách

Nếu bạn muốn biết tại sao nên sử dụng visibility: hidden; trên display: none;, thì đó là vì bạn có thể tạo ảnh động cho chế độ hiển thị. Thuộc tính này chỉ có hai trạng thái là hiddenvisible, nhưng bạn có thể kết hợp thuộc tính này với một thuộc tính khác như transform hoặc opacity để tạo hiệu ứng trượt hoặc mờ dần. Cách này sẽ không hiệu quả với màn hình hiển thị: không có vì thuộc tính hiển thị không thể tạo được.

CSS sau đây chuyển đổi opacity để tạo hiệu ứng mờ dần và rõ dần.

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);
}

Thay vào đó, nếu muốn tạo hiệu ứng chuyển động cho chuyển động, bạn nên cân nhắc việc gói thuộc tính transition trong một truy vấn nội dung nghe nhìn ưu tiên-reduced-motion vì ảnh động có thể gây ra cảm giác buồn nôn, chóng mặt và đau đầu ở một số người dùng.

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);
}

Điều này đảm bảo rằng chỉ những người không thích chuyển động giảm dần mới nhìn thấy ảnh động.

Xem Bước 7: Tạo ảnh động cho danh sách trên CodePen.

Cải thiện định kiểu tiêu điểm

Người dùng bàn phím dựa vào kiểu tiêu điểm của phần tử để xác định hướng và thao tác trên trang. Kiểu lấy nét mặc định tốt hơn là không có kiểu lấy nét (điều này xảy ra nếu bạn đặt outline: none). Tuy nhiên, việc có các kiểu lấy nét tuỳ chỉnh rõ ràng hơn sẽ giúp cải thiện trải nghiệm người dùng.

Dưới đây là giao diện của các kiểu tiêu điểm mặc định trên đường liên kết trong Chrome 103.

Đường viền 2px màu xanh dương bao quanh một đường liên kết được lấy tiêu điểm trong Chrome 103.

Bạn có thể cải thiện điều đó bằng cách cung cấp kiểu của riêng bạn theo màu sắc của riêng bạn. Khi sử dụng :focus-visible thay vì :focus, bạn cho phép trình duyệt quyết định thời điểm thích hợp để hiển thị kiểu lấy nét. Mọi người đều có thể thấy kiểu :focus, dù họ có cần hay không cần sử dụng chuột, bàn phím và thao tác chạm. Với :focus-visible, trình duyệt sẽ sử dụng các phương pháp phỏng đoán nội bộ để quyết định xem chỉ hiển thị những thông tin này cho người dùng bàn phím hay cho mọi người.

/* 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;
}

Hỗ trợ trình duyệt cho :focus-visible

Hỗ trợ trình duyệt

  • Chrome: 86.
  • Cạnh: 86.
  • Firefox: 85.
  • Safari: 15.4.

Nguồn

Đường viền 2px tối có thể nhìn thấy rõ với khoảng cách bên trong.

Có nhiều cách để đánh dấu các mục khi chúng được đặt tiêu điểm. Bạn nên dùng thuộc tính outline vì thuộc tính này không làm hỏng bố cục (điều có thể xảy ra với border) và hoạt động tốt với chế độ tương phản cao trên Windows. Các thuộc tính không hoạt động tốt là background-color hoặc box-shadow, vì chúng có thể không được hiển thị với chế độ cài đặt độ tương phản tuỳ chỉnh.

Một trang web có nền tối với tiêu điểm được làm nổi bật bằng màu tím.
Xem Bước 8: Cải thiện kiểu tiêu điểm trên CodePen.

Xin chúc mừng! Bạn đã xây dựng một giao diện điều hướng chính phù hợp với thiết bị di động, phong phú về mặt ngữ nghĩa, dễ truy cập và thân thiện với thiết bị di động.

Chúng ta luôn có thể cải thiện một số điểm, chẳng hạn như:

Nếu bạn còn nhớ bài viết này bắt đầu như thế nào, với mục tiêu giải pháp nên "không quá đơn giản, cũng không quá phức tạp", thì giờ đây chúng ta sẽ thực hiện nhiệm vụ đó. Tuy nhiên, bạn có thể thiết kế quá mức điều hướng.

Có sự khác biệt rõ ràng giữa thành phần điều hướng và trình đơn. Thành phần điều hướng là tập hợp các đường liên kết để di chuyển trong các tài liệu có liên quan. Trình đơn là tập hợp các thao tác cần thực hiện trong một tài liệu. Đôi khi, các tác vụ này trùng lặp. Bạn có thể có thành phần điều hướng bao gồm nút thực hiện hành động, chẳng hạn như mở cửa sổ phụ, hoặc bạn có thể có trình đơn nơi một hành động đang điều hướng đến một trang khác, chẳng hạn như trang trợ giúp. Khi trường hợp này xảy ra, bạn không được kết hợp nhiều vai trò của ARIA, mà hãy xác định mục đích chính của thành phần rồi chọn thẻ đánh dấu và các vai trò tương ứng.

Phần tử <nav> có vai trò điều hướng ARIA ngầm ẩn, đủ để thông báo rằng phần tử này là một thành phần điều hướng. Tuy nhiên, bạn thường thấy các trang web cũng dùng trình đơn, thanh trình đơn và mục trình đơn. Vì đôi khi chúng ta sử dụng các thuật ngữ này thay thế cho nhau, nên chúng ta nghĩ rằng việc kết hợp chúng để cải thiện trải nghiệm cho người dùng trình đọc màn hình có thể hợp lý. Trước khi chúng ta tìm hiểu lý do khiến điều đó thường không đúng như vậy, hãy cùng xem định nghĩa chính thức về các vai trò này.

Vai trò điều hướng

Tập hợp các thành phần điều hướng (thường là đường liên kết) để điều hướng trong tài liệu hoặc các tài liệu có liên quan.

điều hướng (vai trò) WAI-ARIA 1.1

Vai trò trong trình đơn

Trình đơn thường là danh sách các thao tác hoặc chức năng phổ biến mà người dùng có thể gọi. Vai trò trong trình đơn chỉ phù hợp khi một danh sách các mục trong trình đơn được trình bày theo cách tương tự như trình đơn trên ứng dụng dành cho máy tính.

trình đơn (vai trò) WAI-ARIA 1.1

Vai trò trên thanh trình đơn

Một bản trình bày trình đơn thường vẫn hiển thị và thường hiển thị theo chiều ngang. Vai trò thanh trình đơn được dùng để tạo thanh trình đơn tương tự như thanh trình đơn trong các ứng dụng dành cho máy tính Windows, Mac và Gnome. Một thanh trình đơn dùng để tạo một tập hợp các lệnh thường dùng nhất quán. Tác giả phải đảm bảo rằng hoạt động tương tác với thanh trình đơn tương tự như hoạt động tương tác với thanh trình đơn thông thường trong giao diện người dùng đồ hoạ trên máy tính.

thanh trình đơn (vai trò) WAI-ARIA 1.1

Vai trò mục trong trình đơn

Một lựa chọn trong tập hợp các lựa chọn có trong một trình đơn hoặc thanh trình đơn.

menuitem (vai trò) WAI-ARIA 1.1

Thông số kỹ thuật ở đây rất rõ ràng, hãy sử dụng tính năng điều hướng để điều hướng trong tài liệu hoặc các tài liệu có liên quan và chỉ trình đơn để xem danh sách các thao tác hoặc chức năng tương tự như trình đơn trong các ứng dụng dành cho máy tính. Nếu không xây dựng Google Tài liệu tiếp theo, thì có thể bạn không cần bất kỳ vai trò nào trên trình đơn cho thanh điều hướng chính.

Khi nào bạn có thể dùng thực đơn?

Mục đích chính của các mục trong trình đơn không phải là điều hướng, mà để thực hiện thao tác. Giả sử bạn có một danh sách hoặc bảng dữ liệu và người dùng có thể thực hiện một số thao tác nhất định đối với từng mục trong danh sách. Bạn có thể thêm một nút vào mỗi hàng và hiển thị thao tác khi người dùng nhấp vào nút đó.

<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>

Ý nghĩa của việc sử dụng các vai trò trong trình đơn

Điều thực sự quan trọng là sử dụng các vai trò này trong thực đơn một cách khôn ngoan vì có rất nhiều thứ có thể không ổn.

Các trình đơn đòi hỏi một cấu trúc DOM nhất định. menuitem phải là mục con trực tiếp của menu. Mã sau đây có thể phá vỡ hành vi ngữ nghĩa:

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

Người dùng thông thái mong muốn các phím tắt nhất định hoạt động với các trình đơn và thanh trình đơn. Dựa trên Hướng dẫn về phương pháp ghi nhận quyền tác giả (APG) của ARIA, nội dung này bao gồm:

  • Nhấn phím EnterPhím cách để chọn các mục trong trình đơn.
  • Các phím mũi tên theo mọi hướng để di chuyển giữa các mục.
  • Phím HomeEnd để di chuyển tiêu điểm đến mục đầu tiên hoặc mục cuối tương ứng.
  • a-z để di chuyển tiêu điểm đến mục tiếp theo trong trình đơn bằng một nhãn bắt đầu bằng ký tự đã nhập.
  • Esc để đóng trình đơn.

Nếu trình đọc màn hình phát hiện thấy một trình đơn, thì phần mềm có thể tự động thay đổi chế độ duyệt web, cho phép bạn sử dụng các phím tắt đã đề cập trước đó. Những người dùng trình đọc màn hình chưa có kinh nghiệm có thể không sử dụng được trình đơn vì họ không biết các phím tắt này hoặc cách sử dụng chúng.

Điều này cũng tương tự đối với người dùng bàn phím muốn sử dụng tổ hợp phím ShiftShift + Tab.

Có rất nhiều điều cần xem xét khi bạn tạo trình đơn và thanh trình đơn, về việc liệu có phù hợp để sử dụng chúng ngay từ đầu khi tạo trình đơn và thanh trình đơn hay không. Khi xây dựng một trang web thông thường, bạn chỉ cần phần tử điều hướng có danh sách và các đường liên kết. Điều này cũng áp dụng cho Ứng dụng trang đơn (SPA) hoặc ứng dụng web. Ngăn xếp cơ bản không quan trọng. Trừ phi bạn đang tạo một ứng dụng rất gần với ứng dụng dành cho máy tính, hãy tránh các vai trò trong trình đơn.

Tài nguyên khác

Hình ảnh chính của Mick Haupt