Hướng dẫn này mô tả cách xây dựng một trình đơn điều hướng chính dễ tiếp cận cho 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à có lợi.
Có nhiều cách để xây dựng thành phần điều hướng chính của một trang web, về kiểu, chức năng, cũng như mã đánh dấu và thông tin ngữ nghĩa 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, tính năng này có thể khiến người dùng bối rối hoặc thậm chí cản trở họ truy cập.
Đối với hầu hết trang web, bạn nên xây dựng một cấu trúc 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 một chế độ thiết lập cơ bản và thêm từng lớp đối tượng tính năng cho đến khi cung cấp đủ thông tin, định kiểu 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 áp dụng nguyên tắc cải tiến tăng dần, tức là 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 hoạt động vì lý do nào đó, thì tính năng điều hướng vẫn hoạt động vì tính năng này sẽ quay lại lớp cơ bản 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 có 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.
HTML
<a href="/home">Home</a> <a href="/about-us">About us</a> <a href="/pricing">Pricing</a> <a href="/contact">Contact</a>CSS
/* 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); }
Cách 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 bằng 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 để thao tác, nhưng vẫn còn nhiều điểm cần 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 các chức năng và thông tin bổ sung.
Bạn có thể làm những việc sau:
- Làm nổi bật 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 thành phần điều hướng bằng phím tắt.
- Ẩn thanh đ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 đề của phương pháp này là chỉ truyền tải thông tin về đường liên kết đang hoạt động bằng 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à các trang khác. May mắn là tiêu chuẩn Ứng dụng Internet đa dạng thức hỗ trợ tiếp cận (ARIA) cũng cung cấp một 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 dùng để chỉ định một đường liên kết trong một nhóm đường liên kết phân trang, trong đó đường liên kết được định kiểu trực quan để đại diện cho trang đ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, 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 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);
}
Thông báo số lượng mục
Bằng cách xem phần điều hướng, người dùng có thể biết rằng phần này chỉ chứa 4 đường liên kết. Người dùng trình đọc màn hình bị khiếm thị không thể lấy thông tin này nhanh như vậy. Họ có thể phải xem qua toàn bộ danh sách đườ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 danh sách chứa 40 đường liên kết thì việc này có thể rườm rà. Nếu người dùng trình đọc màn hình biết trước rằng thành phần điều hướng chứa nhiều đường liên kết, thì 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, phần mềm của họ sẽ thông báo nội dung như "danh sách, 4 mục".
Sau đây là bản minh hoạ cách điều hướng bằng trình đọc màn hình NVDA trên Windows.
Bây giờ, bạn phải điều chỉnh kiểu để giao diện trông giống như trước.
/* 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 đó.
- Họ có thể dùng phím tắt để chuyển từ mục này sang mục khác trong danh sách.
- Họ có thể dùng phím 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 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 mục nhất quán 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ả các lợi thế này khi đặt list-style: none. Đây là hành vi có chủ đích. Nhóm WebKit đã quyết định xoá ngữ nghĩa danh sách khi danh sách không giống 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. Một mặt, tính năng điều hướng vẫn có thể sử dụng được và 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ể rất hữu ích trong một số trường hợp. Để đưa ra quyết định đó, bạn nên thử nghiệm tính năng điều hướng với người dùng trình đọc màn hình thực tế và nhận ý kiến phản hồi của họ. Nếu quyết định rằng bạn cần VoiceOver trong Safari hoạt động giống như tất cả các trình đọc màn hình khác, thì bạn có thể giải quyết vấn đề này bằng cách đặt vai trò danh sách ARIA một cách rõ ràng trên <ul>. Thao tác này sẽ khôi phục hành vi về trạng thái trước khi bạn xoá kiểu danh sách. Về mặt hình ảnh, danh sách vẫn giữ nguyên.
<ul role="list">
<li>
<a href="/home">Home</a>
</li>
...
</ul>
Thêm địa danh
Chỉ với một chút nỗ lực, bạn đã cải thiện đáng kể trải nghiệm cho người dùng trình đọc màn hình, nhưng bạn vẫn có thể làm thêm một việc nữa. Về mặt ngữ nghĩa, thành phần điều hướng vẫn chỉ là một danh sách các đường liên kết và khó có thể biết được danh sách cụ thể này là thành phần điều hướng chính của trang web. 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à trình đọc màn hình sẽ thêm một mốc vào trang. Mốc 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 đến. Việc có các điểm mốc trên một trang có thể hữu ích vì 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 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 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 rôto để liệt kê tất cả các mốc trên trang bằng cách nhấn tổ hợp phím VO + U.
Trong danh sách này, bạn sẽ thấy 4 mốc: biểu ngữ là phần tử <header>, điều hướng là <nav>, chính là phần tử <main> và thông tin nội dung là <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 trong giao diện người dùng làm mốc, chẳng hạn như tính năng tìm kiếm trên trang web, thành phần điều hướng cục bộ hoặc phân trang.
Nếu có một trình đơn điều hướng trên toàn trang web, một trình đơn điều hướng cục bộ cho trang và một trình đơn phân trang trên một trang, thì bạn cũng có thể có 3 phần tử <nav>. Điều này không sao, nhưng hiện có ba mốc điều hướng và về mặt ngữ nghĩa, tất cả đều giống nhau. Rất khó để phân biệt chúng, trừ phi bạn biết rõ cấu trúc của trang.
Để phân biệt các thành phần này, bạn nên gắn nhãn 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 đó trong trang, thì bạn có thể sử dụng aria-labelledby và tham chiếu 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>
Chỉ cần một nhãn ngắn gọn là đủ, đừ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.
Ẩn thanh điều hướng trên khung nhìn hẹp
Cá nhân tôi không thích ẩn thành phần điều hướng chính trên khung nhìn hẹp, nhưng nếu danh sách đường liên kết quá dài, thì không có cách nào khác. Nếu 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 biểu tượng bánh hamburger hoặc cả hai. Khi bạn nhấp vào nút này, danh sách sẽ hiện ra hoặc ẩn đi. Nếu biết JavaScript và CSS cơ bản, bạn có thể thực hiện được việc này, nhưng có một số điều về trải nghiệm người dùng và khả năng hỗ trợ tiếp cận mà bạn phải lưu ý.
- Bạn phải ẩn danh sách theo cách dễ tiếp cận.
- Bạn phải có thể điều hướng bằng bàn phím.
- Thanh điều hướng phải cho biết liệu nó có hiển thị hay không.
Thêm nút trình đơn ba gạch ngang
Vì đang tuân theo nguyên tắc cải tiến tăng dần, nên bạn cầ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 tắt JavaScript.
Điều đầu tiên mà thành phần điều hướng cần có là nút trình đơn ba gạch ngang. Bạn tạo thành phần này bằng HTML trong một phần tử mẫu, sao chép thành phần này bằng JavaScript rồi thêm vào thành phần điều hướng.
<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>
- Thuộc tính
aria-expandedcho phần mềm trình đọ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. aria-labelcung cấp cho nút một tên thành phần hỗ trợ tiếp cận, một văn bản thay thế cho biểu tượng bánh mì kẹp thịt.- Bạn ẩn
<svg>khỏi công nghệ hỗ trợ bằng cách sử dụngaria-hiddenvì công nghệ này đã có nhãn văn bản doaria-labelcung cấp. aria-controlscho công nghệ hỗ trợ biết phần tử mà nút điều khiển (công nghệ hỗ trợ này có hỗ trợ thuộc tính, ví dụ: 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);
- Người dùng 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.
- Bạn cần sử dụng
insertBeforethay vìappendChildvì nút này phải là phần tử đầ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ẽ muốn tập trung 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 đó 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 này 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);
}
Đang ẩn danh sách
Trước khi ẩn danh sách, hãy định vị và tạo kiểu cho thành phần đ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.
Trước tiên, hãy xoá <nav> khỏi luồng tự nhiên của trang và đặt phầ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 một thuộc tính tuỳ chỉnh mới (—-nav-list-layout). Bố cục mặc định 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;
}
Thanh điều hướng của bạn sẽ có dạng như sau trên khung nhìn hẹp.
Rõ ràng là danh sách này cần một số 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-color và box-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ư sau trên khung nhìn hẹp, giống thanh bên hơn là danh sách đơn giản.
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 nên ẩn toàn bộ thành phần điều hướng, vì việc ẩn thành phần đ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 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 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 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 các đường liên kết không thể lấy tiêu điểm 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 để các đường liên kết 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 phần tử đó về mặt hình ảnh và khiến người dùng không thể truy cập, do đó ẩn phần tử đó đối với tất cả người dùng.
Tạo ảnh động cho danh sách
Nếu bạn đang thắc mắc tại sao nên sử dụng visibility: hidden; thay vì display: none;, thì lý do 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à hidden và visible, 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 display: none vì thuộc tính display không thể tạo ảnh động.
Hiệu ứng chuyển đổi CSS sau đây 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);
}
Nếu muốn tạo ảnh động cho chuyển động, bạn nên cân nhắc gói thuộc tính transition trong truy vấn đa phương tiện prefers-reduced-motion vì ảnh động có thể gây ra buồn nôn, chóng mặt và đau đầu cho 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 có lựa chọn ưu tiên về việc giảm chuyển động mới thấy ảnh động.
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 một trang. Kiểu lấy tiêu điểm mặc định tốt hơn là không có kiểu lấy 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 lấy tiêu điểm tuỳ chỉnh dễ thấy hơn sẽ cải thiện trải nghiệm người dùng.
Dưới đây là giao diện của kiểu tiêu điểm mặc định trên đường liên kết trong Chrome 103.
Bạn có thể cải thiện điều đó bằng cách cung cấp kiểu riêng 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ị kiểu lấy tiêu điểm. Kiểu :focus sẽ hiển thị cho mọi người, người dùng chuột, bàn phím và thao tác chạm, bất kể họ có cần hay không. Với :focus-visible, trình duyệt sẽ sử dụng phương pháp phỏng đoán nội bộ để quyết định xem có nên hiển thị các chỉ báo này cho người dùng bàn phím hay cho tất cả mọi người hay không.
/* 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
Có nhiều cách để làm nổi bật các mục khi chúng được lấy 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 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 hiệu quả là background-color hoặc box-shadow, vì chúng có thể không hiển thị khi bạn dùng chế độ cài đặt độ tương phản tuỳ chỉnh.
Xin chúc mừng! Bạn đã xây dựng một thành phần điều hướng chính có khả năng cải tiến tăng 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ụ:
- Bạn có thể cân nhắc bẫy tiêu điểm bên trong thành phần điều hướng hoặc đặt phần còn lại của trang thành inert trên khung nhìn hẹp.
- Bạn có thể thêm đường liên kết bỏ qua ở đầu trang để người dùng bàn phím có thể bỏ qua phần điều hướng.
Nếu bạn nhớ lại phần mở đầu của bài viết này, với mục tiêu là giải pháp "không quá đơn giản cũng không quá phức tạp", thì đó chính là giải pháp mà chúng ta đang có. Tuy nhiên, bạn có thể thiết kế quá mức một thành phần điều hướng.
Thanh điều hướng so với trình đơn
Có sự khác biệt rõ ràng giữa thành phần điều hướng và trình đơn. Thanh điều hướng là tập hợp các đường liên kết để di chuyển giữa các tài liệu 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 nhiệm vụ này trùng lặp. Bạn có thể có một thành phần đ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ụ, hoặc bạn có thể có một trình đơn trong đó một hành động là điều hướng đến một trang khác, chẳng hạn như trang trợ giúp. Trong trường hợp đó, bạn không nên kết hợp các vai trò ARIA mà hãy xác định mục đích chính của thành phần rồi chọn mã đánh dấu và vai trò tương ứng.
Phần tử <nav> có vai trò ARIA ngầm định là điều hướng, đủ để cho biết rằng phần tử này là một thành phần điều hướng, nhưng bạn thường thấy các trang web cũng sử dụng menu, menubar và menuitem. 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 chúng để 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 tại sao thường không phải 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 phần tử điều hướng (thường là đường liên kết) để điều hướng tài liệu hoặc các tài liệu liên quan.
navigation (role) WAI-ARIA 1.1
Vai trò 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ò trình đơn 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ò thanh trình đơn
Một 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 được dùng để tạo một 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. Thanh trình đơn được dùng để tạo một tập hợp nhất quán các lệnh thường dùng. 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 thông thường với thanh trình đơn trong giao diện người dùng đồ họa trên máy tính.
menubar (vai trò) WAI-ARIA 1.1
Vai trò menuitem
Một lựa chọn trong một tập hợp các lựa chọn có trong trình đơn hoặc thanh trình đơn.
menuitem (vai trò) WAI-ARIA 1.1
Quy cách ở đây rất rõ ràng, hãy sử dụng thành phần điều hướng để điều hướng tài liệu hoặc tài liệu liên quan và trình đơn chỉ cho danh sách các thao tác hoặc chức năng tương tự như trình đơn trong ứ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, có thể bạn không cần bất kỳ vai trò trình đơn nào cho thành phần điều hướng chính.
Khi nào thì nên dùng trình đơ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 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 vai trò trình đơn
Bạn cần phải 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 vấn đề.
Trình đơn yêu cầu một cấu trúc DOM nhất định. menuitem phải là mục con trực tiếp của menu. Đoạn 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 am hiểu công nghệ 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 biên soạn ARIA (APG), các vai trò này bao gồm:
- Enter và Phí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 Home và End để di chuyển tiêu điểm đến mục đầu tiên hoặc mụ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, thì 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 đó. 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, những người có thể mong đợi rằng họ có thể sử dụng Shift và Shift + Tab.
Có nhiều điều cần cân nhắc khi bạn tạo trình đơn và thanh trình đơn, trong đó việc có nên sử dụng chúng hay không là điều quan trọng nhất. 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
- Sửa danh sách của Scott O'hara.
- Don't Use ARIA Menu Roles for Site Nav (Không sử dụng vai trò trình đơn ARIA cho thành phần điều hướng trang web) của Adrian Roselli.
- Trình đơn và nút trình đơn của Heydon Pickering.
- Trình đơn WAI-ARIA và lý do bạn nên xử lý chúng một cách cẩn thận của Marco Zehe.
- Ẩn nội dung một cách có trách nhiệm của Kitty Giraudel.
- :focus-visible Is Here của Matthias Ott.