Hướng dẫn này mô tả cách tạo một thanh điều hướng chính hỗ trợ tiếp cận của 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.
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 muốn tạo một thứ gì đó 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 hoạt động vì lý do nào đó, thì tính năng điều hướng vẫn sẽ hoạt động vì nó 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 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);
}
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 thanh điều hướng trên khung nhìn hẹp.
- Cải thiện định kiểu cho 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 giá trị và thuộc tính 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);
}
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ể nhận được thông tin này nhanh chóng như vậy. Họ có thể phải xem xét 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 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 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 để giao diện trở lại 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 đó.
- 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 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 số bốn").
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 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ả những ưu điểm này khi đặt list-style: none
. Đây là thiết kế của chúng tôi. 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 giố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ẽ huỷ bỏ 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ống như cũ.
<ul role="list">
<li>
<a href="/home">Home</a>
</li>
...
</ul>
Thêm điểm mốc
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. Tuy nhiên, bạn vẫn có thể làm thêm một việc nữa. Về mặt ngữ nghĩa, thanh điều hướng vẫn chỉ là một danh sách đường liên kết và khó có thể nhận ra rằng danh sách cụ thể này là thanh đ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ố ưu điểm. Đá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. Điểm đánh dấu 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 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 sang điểm mố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.
Trong danh sách này, bạn có thể thấy 4 mốc: banner là phần tử <header>
, navigation là <nav>
, main là thành phần <main>
và thông tin nội dung là <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 đó đượ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. 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.
Để 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. Hãy 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 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. Nếu trường hợp đó xảy ra, 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 thịt hoặc 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.
- Bạn phải có thể điều hướng 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.
<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-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. aria-label
đặt tên cho nút được gọi là tên có thể truy cập, một văn bản thay thế cho biểu tượng bánh mì kẹp.- Bạn ẩn
<svg>
khỏi công nghệ hỗ trợ tiếp cận bằng cách sử dụngaria-hidden
vì<svg>
đã có nhãn văn bản doaria-label
cung cấp. 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);
- 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.
- Bạn cần sử dụng
insertBefore
thay vìappendChild
vì nút này phải là phần tử đầu tiên trong thanh đ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 này chỉ hiển thị trên các 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);
}
Ẩ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 ở 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)
. 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.
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-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 các khung nhìn hẹp, giống như một thanh bên hơn là một 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 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 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. 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.
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;
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à 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 hiệu ứng mờ dần. Điều đó sẽ không hoạt động với display: none vì thuộc tính hiển thị không thể tạo ảnh động.
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 thích giảm chuyển động mới nhìn 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 phần tử để xác định hướng và thao tác 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 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 các kiểu của riêng mình 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
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 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.
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ụ:
- Bạn có thể cân nhắc giữ tiêu điểm bên trong thanh điều hướng hoặc làm cho phần còn lại của trang không hoạt động trên các khung nhìn hẹp.
- Bạn có thể thêm đường liên kết bỏ qua ở đầu trang để cho phép người dùng bàn phím bỏ qua thao tác điều hướng.
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á kỹ lưỡng cho một thành phần điều hướng.
Điều hướng so với trình đơn
Có sự khác biệt rõ ràng giữa các 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 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 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ò của 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.
trình đơn (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ò menuitem
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 rất rõ ràng ở đây, 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à chỉ sử dụng trình đơn cho danh sách 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 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.
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ể làm hỏng 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ạo mong muốn một số phím tắt hoạt động với các 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:
- Enter và Space để 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 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, 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à các đường liên kết. Điều này cũng áp dụng cho Ứng dụng một trang (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 lỗi danh sách của Scott O'hara.
- Đừng sử dụng vai trò trình đơn ARIA cho đ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ý thật 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 đã có mặt của Matthias Ott.
Hình ảnh chính của Mick Haupt