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 và cách sử dụng các thuộc tính ARIA đôi khi có thể gây hại nhiều hơn lợi.

Manuel Matuzović
Manuel Matuzović

Có nhiều cách để tạo thanh điều hướng chính của trang web, xét về kiểu, chức năng, cũng như thông tin ngữ nghĩa và mã đánh dấu cơ bản. Nếu cách triển khai quá tối giản, thì cách này 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 tốt. Nếu được thiết kế quá phức tạp, giao diện có thể gây nhầm lẫn cho người dùng hoặc thậm chí khiến họ không thể truy cập vào giao diện đó.

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

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

Trong hướng dẫn này, bạn sẽ bắt đầu bằng cách thiết lập cơ bản và thêm các tính năng theo từng lớp cho đến khi bạn cung cấp đủ thông tin, kiểu dáng và chức năng để làm hài lòng hầu hết người dùng. Để đạt được điều đó, bạn cần sử dụng nguyên tắc cải tiến dần dần. Nguyên tắc này cho biết rằng bạn bắt đầu bằng giải pháp cơ bản và mạnh mẽ nhất, sau đó dần dần thêm 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

Để có một thành phần điều hướng cơ bản, bạn cần hai thứ: các phần tử <a> và một 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.

Phương thức này phù hợp với hầu hết người dùng, bất kể họ truy cập vào trang web theo cách nào. Bạn có thể sử dụng chuột, bàn phím, thiết bị cảm ứng hoặc trình đọc màn hình để điều hướng, nhưng vẫn có thể cải thiện. 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 một đ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 bảng điều hướng bằng lối tắt.
  • Ẩn điều hướng trên khung nhìn hẹp.
  • Cải thiện kiểu tiêu điểm.

Làm nổi bật trang đang hoạt động

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

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

Vấn đề với phương pháp này là nó chỉ truyền tải thông tin về đường liên kết đang hoạt động một cách trực quan. Người dùng trình đọc màn hình khiếm thị không thể phân biệt được 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 thuộc tính và giá trị aria-current="page" 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ị. [Accessible Rich Internet Applications (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 hiện sẽ thông báo 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ỉ "đường 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 hiệu ứ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: Làm nổi bật trang đang hoạt động trên CodePen.

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

Khi xem thanh điều hướng, người dùng bình thường có thể biết rằng thanh này chỉ chứa 4 đườ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. Họ có thể phải xem xét toàn bộ danh sách đường liên kết. Điều nà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 danh sách chứa 40 đường liên kết thì việc này có thể sẽ rất rườm rà. Nếu người dùng trình đọc màn hình biết trước rằng thanh đ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ính năng tìm kiếm 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, phần mềm của họ sẽ thông báo nội dung như "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 trình đọc màn hình NVDA 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ể biết tổng số mục trước khi tương tác với các mục đó.
  • Người dùng có thể sử dụng phím tắt để chuyển từ mục danh sách này sang mục danh sách khác.
  • 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, hai trong số bốn").

Ngoài ra, nếu trang được trình bày mà không có CSS, danh sách sẽ hiển thị các đường liên kết dưới dạng một nhóm các mục nhất quán thay vì chỉ là một đống đườ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 lợi thế 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 danh sách khi danh sách không giống như danh sách. Tuỳ thuộc vào độ phức tạp của thành phần điều hướng, đây có thể là vấn đề hoặc không phải là vấn đề. Mặt khác, bạn vẫn có thể sử dụng tính năng điều hướng và tính năng này 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ả 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 thiết lập rõ ràng vai trò danh sách ARIA trên <ul>. Thao tác này sẽ huỷ bỏ 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 đã thực hiện những cải tiến tuyệt vời cho người dùng trình đọc màn hình, nhưng vẫn còn một việc nữa bạn có thể làm. Điều hướng về mặt ngữ nghĩa 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à thành phần đ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 nội dung như "điều hướng" khi người dùng tương tác với trình đọc màn hình và thêm một điểm 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 đó. Việc có các điểm mốc trên trang có thể hữu ích vì nó 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 khu vực quan trọng trên trang mà không cần 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 này sang điểm mốc khác bằng cách nhấn phím D trong NVDA. Trong VoiceOver, bạn có thể sử dụng con quay để liệt kê tất cả các điểm đánh dấu trên trang bằng cách nhấn tổ hợp phím VO + U.

Danh sách gồm 4 mốc: biểu ngữ, điều hướng, chính, thông tin nội dung.
Bộ lọc 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 được quá dài, bạn chỉ nên đánh dấu các phần quan trọng của giao diện người dùng làm điểm đánh dấu, chẳng hạn như tính năng tìm kiếm trang web, điều hướng cục bộ hoặc phân trang.

Nếu có một thanh điều hướng trên toàn trang web, một thanh điều hướng cục bộ cho trang và một tính 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 đó không sao, nhưng hiện có 3 mốc điều hướng và về mặt ngữ nghĩa, chúng đều giống nhau. Rất khó để phân biệt các phần tử này, trừ phi bạn nắm rõ cấu trúc của trang.

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

Để phân biệt các thành phần này, bạn nên gắn nhãn cho 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>

Bạn chỉ cần một nhãn ngắn gọn, đừng quá dài dòng. Bỏ qua các biểu thức như "điều hướng" 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ữ", "thanh điều hướng chính", "chính", "điều hướng trang", "chọn điều hướng trang" và "thông tin nội dung".
Xem Bước 4: Thêm địa danh trên CodePen.

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

Cá nhân tôi không thích ẩn thanh điều hướng chính trên các khung nhìn hẹp, nhưng nếu danh sách đường liên kết quá dài thì không còn cách nào khác. Trong trường hợp đó, thay vì danh sách, người dùng sẽ thấy một nút có nhãn "Trình đơn" hoặc biểu tượng bánh mì kẹp hoặc một tổ hợp. 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, thì đó là một nhiệm vụ có thể thực hiện được, nhưng bạn phải chú ý đến một số điều liên quan đến trải nghiệm người dùng và khả năng hỗ trợ tiếp cận.

  • Bạn phải ẩn danh sách theo cách dễ truy cập.
  • 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 thông báo xem thành phần đó có hiển thị hay không.

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

Vì đang tuân theo nguyên tắc cải tiến dần, nên bạn cần đảm bảo rằng hệ thống điều hướng vẫn hoạt động và có ý nghĩa ngay cả khi JavaScript bị tắt.
Điều đầu tiên mà hệ thống điều hướng cần là một nút bánh mì. Bạn tạo thành phần này trong HTML trong một phần tử mẫu, sao chép thành phần này trong JavaScript và thêm thành phần này vào thanh điều hướng.

Một trang hiển thị nút bánh mì kẹp thịt.
Kết quả: Thay vì các đường liên kết, thanh điều hướng sẽ hiển thị một nút bánh mì kẹp trên các 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 liệu 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 được hỗ trợ (ví dụ: JAWS) và nút kiểm soát phần tử nào.
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 sẽ thuận tiện hơn khi có thể đóng bảng đ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 phím Tab sau khi nhấp vào nút, họ sẽ đặt tiêu điểm vào mục đầu tiên trong danh sách. Nếu nút nằm sau danh sách, thì điều đó sẽ không xảy ra.

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 trên CodePen.

Ẩn danh sách

Trước khi bạn ẩn danh sách, hãy định vị và tạo kiểu cho thanh điều hướng và danh sách để bố cục được tối ưu hoá cho 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 xoá <nav> khỏi luồng tự nhiên của trang và đặt nó ở 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 các khung nhìn hẹp bằng cách thêm một thuộc tính tuỳ chỉnh mới (—-nav-list-layout). Theo mặc định, bố cục là cột 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 hiển thị danh sách điều hướng và nút bánh mì kẹp.
Cả nút bánh mì và danh sách đều được đặt ở góc trên cùng của khung nhìn.

Danh sách này rõ ràng cần một số Dịch vụ so sánh giá (CSS). Chúng ta sẽ di chuyển nó 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 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. Điều quan trọng là chỉ ẩn danh sách chứ không phải toàn bộ thanh điều hướng vì việc ẩn thanh điều hướng cũng có nghĩa là ẩn một mốc quan trọng.

Trước đó, bạn đã thêm một sự kiện nhấp 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 nội dung 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. Các thuộc tính này đảm bảo rằng người dùng không thể lấy tiêu điểm vào các đường liên kết khi thanh đ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 có thể truy cập được bằng bàn phím, điều này sẽ gây nhầm lẫn và khó chịu. Việc sử dụng visibility hoặc display sẽ ẩn thành phần hiển thị và khiến thành phần đó không truy cập được, do đó sẽ ẩn thành phần đó cho 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 thắc mắc tại sao nên sử dụng visibility: hidden; thay vì 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.

Các hiệu ứng chuyển đổi CSS sau đây opacity để tạo hiệu ứng mờ dần và mờ 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);
}

Nếu muốn tạo ảnh động chuyển động, bạn nên cân nhắc gói thuộc tính transition trong truy vấn nội dung đa phương tiện prefers-reduced-motion vì ảnh động có thể kích hoạt 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 ưu tiên giảm chuyển động mới thấy ảnh động.

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

Cải thiện 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 các phần tử để định hướng và điều hướng trên trang. Kiểu tiêu điểm mặc định tốt hơn so với không có kiểu tiêu điểm (điều này xảy ra nếu bạn đặt outline: none), nhưng việc có kiểu tiêu điểm tuỳ chỉnh rõ ràng hơn sẽ 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 màu xanh dương 2px xung quanh đườ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. Bằng cách 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ị các kiểu tiêu điểm. Tất cả người dùng, người dùng chuột, bàn phím và cảm ứng đều có thể nhìn thấy các kiểu :focus, bất kể họ có cần hay không. Với :focus-visible, trình duyệt sử dụng các phương pháp phỏng đoán nội bộ để quyết định chỉ hiển thị cho người dùng bàn phím hay cho tất cả 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.
  • Edge: 86.
  • Firefox: 85.
  • Safari: 15.4.

Nguồn

Đường viền 2px màu tối rõ ràng 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 sử 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 này 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 thanh điều hướng chính được cải tiến dần, giàu ngữ nghĩa, dễ tiếp cận và thân thiện với thiết bị di động.

Luôn có những điểm có thể cải thiện, ví dụ:

Nếu bạn còn nhớ cách bắt đầu bài viết này, mục tiêu của chúng ta là giải pháp "không quá đơn giản cũng không quá phức tạp". Đó chính là giải pháp mà chúng ta đang tìm kiếm. 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, những nhiệm vụ này trùng lặp với nhau. Bạn có thể có một thanh điều hướng cũng bao gồm một nút thực hiện một hành động, chẳng hạn như mở cửa sổ phương thức hoặc bạn có thể có một trình đơn trong đó một hành động sẽ điều hướng đến một trang khác, chẳng hạn như trang trợ giúp. Trong trường hợp đó, điều quan trọng là bạn không được kết hợp các vai trò ARIA, mà phải xác định mục đích chính của thành phần và chọn phù hợp với mã đánh dấu và vai trò.

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

navigation (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ò của trình đơn là phù hợp khi 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.

menu (vai trò) WAI-ARIA 1.1

Vai trò của thanh trình đơn

Một trình bày trình đơn thường hiển thị và thường được trình bày theo chiều ngang. Vai trò thanh trình đơn dùng để tạo thanh trình đơn tương tự như các thanh trình đơn trong các ứng dụng dành cho máy tính Windows, Mac và Gnome. Thanh trình đơn được 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ả nên đả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, sử dụng điều hướng để điều hướng tài liệu hoặc các tài liệu có liên quan và chỉ trình đơn cho danh sách các tác vụ 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 để bàn. Nếu không tạo Google Tài liệu tiếp theo, có thể bạn không cần bất kỳ vai trò trình đơn nào cho bảng đ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à là để thực hiện các 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 trên 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ị các hành động 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>

Hệ quả của việc sử dụng vai trò trình đơn

Bạn cần sử dụng các vai trò trình đơn này một cách khôn ngoan vì có thể xảy ra nhiều lỗi.

Trình đơn cần có 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 tinh ý mong muốn một số phím tắt nhất định hoạt động với trình đơn và thanh trình đơn. Dựa trên Hướng dẫn về các phương pháp tạo nội dung ARIA (APG), các phương pháp 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.
  • Các phím Home (Bắt đầu) và End (Kết thúc) để di chuyển tiêu điểm đến mục đầu tiên hoặc cuối cùng tương ứng.
  • a-z để di chuyển tiêu điểm đến mục trình đơn tiếp theo có 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, phần mềm có thể tự động thay đổi chế độ duyệt web, cho phép 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 các phím tắt đó.

Điều này cũng tương tự đối với người dùng bàn phím có thể mong đợi rằng họ có thể sử dụng phím Shift và tổ hợp phím Shift + Tab.

Có rất nhiều điều cần cân nhắc khi bạn tạo trình đơn và thanh trình đơn, trước tiên là liệu việc sử dụng các thành phần này có phù hợp 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à đườ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 xây dựng một ứng dụng rất giống với ứng dụng dành cho máy tính, hãy tránh sử dụng vai trò trình đơn.

Tài nguyên khác

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