Tập trung

Theo mặc định, các phần tử tương tác, trong đó có các thành phần điều khiển biểu mẫu, đường liên kết và nút, có thể làm tâm điểm và gắn thẻ vào được. Phần tử có thể gắn thẻ là một phần trong thứ tự điều hướng tâm điểm theo tuần tự của tài liệu. Các phần tử khác ở dạng tĩnh, nghĩa là không tương tác. Với các thuộc tính HTML, bạn có thể làm cho các phần tử tương tác ở dạng trơ và làm cho các phần tử trơ có khả năng tương tác.

Theo mặc định, thứ tự tiêu điểm điều hướng giống như thứ tự hình ảnh (tức là thứ tự mã nguồn). Có các thuộc tính HTML có thể thay đổi thứ tự này, còn các thuộc tính CSS có thể thay đổi thứ tự hình ảnh của nội dung. Việc thay đổi thứ tự thẻ bằng HTML hoặc thứ tự hiển thị hình ảnh bằng CSS có thể gây hại cho trải nghiệm người dùng.

Không được thay đổi thứ tự thẻ thực tế và được nhận thấy bằng CSS và HTML. Như 2 ví dụ sau đây minh hoạ, thứ tự thẻ khác với thứ tự dự kiến sẽ gây nhầm lẫn cho người dùng và gây khó chịu cho trải nghiệm người dùng.

Trong ví dụ này, giá trị của thuộc tính tabindex đã làm cho thứ tự thẻ trở nên lộn xộn:

Trong ví dụ này, CSS đã tạo ra sự phân kỳ giữa thứ tự thẻ và thứ tự hình ảnh của nội dung:

Phần khai báo flex-flow: row-reverse; đã đảo ngược thứ tự hình ảnh. Ngoài ra, thuộc tính order của CSS đã được áp dụng cho từ thứ 6, "This" (Đây là từ) đã di chuyển một từ đó theo cách trực quan. Trình tự thẻ là thứ tự của mã, thứ tự này không còn khớp với thứ tự hình ảnh, tạo ra sự ngắt kết nối cho người dùng bàn phím.

Tạo các phần tử trơ có tính tương tác

Bạn có thể thêm các thuộc tính contenteditabletabindex (là các thuộc tính chung) vào bất kỳ phần tử nào để các thuộc tính này có thể làm tâm điểm trong quá trình này. Bạn cũng có thể lấy tiêu điểm bằng chuột hoặc con trỏ bằng cách đặt thuộc tính autofocus hoặc đặt theo tập lệnh, chẳng hạn như bằng element.focus().

Thuộc tính tabindex

Thuộc tính chung tabindex (được giới thiệu trong thuộc tính) cho phép các phần tử không thể nhận tiêu điểm để lấy tiêu điểm, thường là bằng phím Tab. Do đó, sẽ có tên này.

Thuộc tính tabindex nhận giá trị là số nguyên. Giá trị âm làm cho một phần tử có thể làm tâm điểm nhưng không thể gắn thẻ. Giá trị tabindex của 0 giúp phần tử có thể làm tâm điểm và gắn thẻ được, thêm phần tử mà phần tử được áp dụng vào thứ tự điều hướng tâm điểm tuần tự theo thứ tự mã nguồn. Giá trị 1 trở lên sẽ làm cho phần tử có thể làm tâm điểm và gắn thẻ được, nhưng thêm phần tử đó vào trình tự ưu tiên thẻ và như chúng ta đã thấy ở trên, bạn nên tránh.

Trên trang này, nút chia sẻ, <share-action>, là một phần tử tuỳ chỉnh. tabindex="0" thêm phần tử không thể lấy làm tâm điểm như bình thường này vào thứ tự thẻ mặc định trên bàn phím:

<share-action authors="@front-end.social/@estellevw" data-action="click" data-category="web.dev" data-icon="share" data-label="share, mastodon" role="button" tabindex="0">
  <svg aria-label="share" role="img" xmlns="http://www.w3.org/2000/svg">
    <use href="#shareIcon" />
  </svg>
  <span>Share</span>
</share-action>

Trang này có một phần tử tuỳ chỉnh khác: phần điều hướng cục bộ có một phần tử tuỳ chỉnh có giá trị tabindex âm:

<web-navigation-drawer type="standard" tabindex="-1">

Thuộc tính tabindex mang giá trị âm giúp phần tử này có thể làm tâm điểm nhưng không thể gắn thẻ. Phần tử có thể nhận tiêu điểm, chẳng hạn như thông qua HTMLElement.focus(), nhưng không thuộc thứ tự điều hướng tâm điểm tuần tự. Quy ước cho các phần tử có thể làm tâm điểm, không thể gắn thẻ là sử dụng tabindex="-1". Xin lưu ý rằng nếu bạn thêm tabindex="-1" vào một phần tử tương tác, thì thành phần này sẽ không thể gắn thẻ được nữa.

Bạn có thể dùng phương thức element.focus() để đặt tiêu điểm vào các phần tử có thể làm tâm điểm. Xin lưu ý rằng trình duyệt sẽ cuộn các phần tử được đặt tiêu điểm vào khung hiển thị. Vì lý do này, bạn nên tránh sử dụng element.focus({preventScroll:true}), vì việc tập trung vào một phần tử không hiển thị sẽ mang lại trải nghiệm không tốt cho người dùng.

Nếu bạn muốn truy vấn tài liệu để tìm phần tử nào hiện được lấy tiêu điểm, hãy sử dụng thuộc tính Document.activeElement chỉ có thể đọc.

Các phần tử có tabindex từ 1 trở lên sẽ được đưa vào một trình tự thẻ riêng biệt. Như bạn sẽ thấy trong Codepen, quá trình gắn thẻ bắt đầu theo một trình tự riêng, theo thứ tự giá trị thấp nhất đến giá trị cao nhất, trước khi trải qua các giá trị đó theo trình tự thông thường (không có tập tabindex nào hoặc tabindex="0") theo thứ tự nguồn:

tabindex mang giá trị dương sẽ đặt phần tử vào trình tự lấy nét ưu tiên. Điều này có thể gây ra tình trạng hỗn loạn về thứ tự tiêu điểm. Tránh sửa đổi đơn đặt hàng DOM bằng tabindex. Thứ tự thẻ không chỉ có thể bị thay đổi mà tạo ra trải nghiệm người dùng kém mà nhà phát triển còn gặp khó khăn trong việc quản lý và duy trì.

Thuộc tính contenteditable

Thuộc tính contenteditable đã được thảo luận trước đó. Việc đặt contenteditable="true" trên bất kỳ phần tử nào sẽ giúp phần tử đó có thể chỉnh sửa, lấy làm tâm điểm và tuân theo thứ tự thẻ. Hành vi lấy tiêu điểm tương tự như thiết lập tabindex="0", nhưng không giống nhau. Các phần tử contenteditable lồng nhau có thể làm tâm điểm nhưng không thể gắn thẻ. Để làm cho một phần tử contenteditable lồng nhau có thể gắn thẻ, hãy thêm tabindex="0". Thao tác này sẽ thêm phần tử này vào thứ tự điều hướng tâm điểm tuần tự.

Tập trung vào các phần tử tương tác

Thuộc tính autofocus

Mặc dù boolean autofocus là một thuộc tính toàn cục có thể đặt cho bất kỳ phần tử nào, nhưng thuộc tính này không làm cho phần tử trơ có khả năng tương tác. Khi trang tải, phần tử có thể làm tâm điểm đầu tiên với tập hợp thuộc tính autofocus sẽ nhận được tiêu điểm, miễn là phần tử đó đang hiển thị và không được lồng trong một <dialog>.

Việc tự động đặt tiêu điểm vào nội dung có thể gây nhầm lẫn. Khi bạn đặt autofocus trên một thành phần điều khiển biểu mẫu, thành phần điều khiển biểu mẫu đó sẽ cuộn vào khung hiển thị khi tải trang. Tất cả người dùng của bạn, bao gồm cả người dùng trình đọc màn hình và người dùng có khung nhìn nhỏ, có thể không "xem" hướng dẫn cho biểu mẫu, thậm chí có thể cuộn qua nhãn hiển thị thường thấy của kiểm soát biểu mẫu. Thuộc tính autofocus không thay đổi thứ tự điều hướng tâm điểm theo tuần tự của tài liệu. Các phần tử trong trình tự xuất hiện trước phần tử được tự động lấy nét sẽ bị bỏ qua. Vì những lý do này, bạn không nên thêm thuộc tính autofocus.

Trường hợp ngoại lệ đối với đề xuất "không sử dụng autofocus" là thêm thuộc tính autofocus trong các phần tử <dialog>. Khi một hộp thoại được mở ra, trình duyệt sẽ tự động đặt tiêu điểm vào phần tử tương tác có thể làm tâm điểm đầu tiên trong <dialog>, nghĩa là không cần thiết autofocus cho một phần tử. Nếu bạn muốn đảm bảo một phần tử tương tác cụ thể trong hộp thoại sẽ nhận được tiêu điểm khi hộp thoại mở ra, hãy thêm thuộc tính autofocus vào phần tử đó.

<dialog open>
  <form method="dialog">
    <button type="submit" autofocus>close</button>
  </form>
</dialog>

Thuộc tính autofocus được đặt trên <button> đóng đảm bảo rằng thuộc tính này sẽ nhận được tiêu điểm khi hộp thoại được mở. Là phần tử đầu tiên trong hộp thoại, nó sẽ nhận được tiêu điểm trong mọi trường hợp. Theo mặc định, khi một hộp thoại được mở, phần tử có thể làm tâm điểm đầu tiên trong hộp thoại sẽ nhận được tiêu điểm trừ phi một phần tử khác trong hộp thoại đã đặt thuộc tính autofocus.

Làm cho các phần tử tương tác ở dạng trơ

Ngoài ra, còn có các thuộc tính HTML có thể xoá các phần tử tương tác khỏi trình tự thẻ. Việc thêm thuộc tính tabindex phủ định vào các phần tử có thể làm tâm điểm, thêm thuộc tính disabled để hỗ trợ các chế độ điều khiển biểu mẫu và thêm thuộc tính inert chung vào một vùng chứa đều khiến các phần tử không thể gắn thẻ. Ba thuộc tính này KHÔNG thể thay thế cho nhau.

Giá trị tabindex âm

Như chúng ta đã tìm hiểu ở trên, thuộc tính tabindex mang giá trị âm giúp một phần tử có thể làm tâm điểm nhưng không thể gắn thẻ. Mặc dù bạn không cần thêm tabindex="0" vào một phần tử có thể làm tâm điểm theo mặc định, bao gồm cả đường liên kết, nút, thành phần điều khiển biểu mẫu và các phần tử contenteditable; việc thêm tabindex có giá trị âm sẽ xoá các phần tử thường có thể gắn thẻ khỏi thứ tự điều hướng tâm điểm tuần tự.

Giá trị tabindex âm ngăn người dùng bàn phím tập trung vào các phần tử tương tác, nhưng không tắt phần tử đó. Người dùng con trỏ vẫn có thể tập trung vào phần tử này. Để tắt một phần tử, hãy sử dụng thuộc tính disabled.

Đã tắt

Thuộc tính boolean disabled (tắt) giúp các chế độ điều khiển biểu mẫu được áp dụng và các thành phần con cháu của chúng (nếu có) không thể làm tâm điểm. Các chế độ kiểm soát biểu mẫu đã tắt sẽ không thể lấy tiêu điểm, không nhận được các sự kiện nhấp chuột và không được gửi khi bạn gửi biểu mẫu. Lưu ý: disabled không phải là thuộc tính chung. Thay đổi này áp dụng cho <button>, <input>, <optgroup>, <option>, <select>, <textarea>, các phần tử tuỳ chỉnh liên kết với biểu mẫu và <fieldset>. Khi bạn đặt trên <optgroup> hoặc <fieldset>, mọi thành phần điều khiển biểu mẫu con sẽ bị tắt, ngoại trừ nội dung trong <legend> đầu tiên của <fieldset>.

Các phần tử hỗ trợ disabled cũng có thể nhắm mục tiêu bằng các lớp giả lập :disabled:enabled. Các phần tử bị vô hiệu hoá bằng thuộc tính disabled thường có kiểu màu xám nhạt thông qua biểu định kiểu tác nhân người dùng, ngay cả khi bạn đặt accent-color.

Là một thuộc tính boolean, nên nếu thuộc tính này xuất hiện thì phần tử được bật theo cách khác sẽ bị vô hiệu hoá; bạn không thể thiết lập thuộc tính này thành false. Để bật lại một phần tử đã bị vô hiệu hoá, bạn phải xoá thuộc tính này, thường là qua Element.removeAttribute('disabled').

Thuộc tính HTMLInputElement.disabled cho phép bạn kiểm tra xem liệu dữ liệu đầu vào có bị tắt hay không. Vì disabled không phải là một thuộc tính chung nên không được kế thừa từ HTMLElement, nhưng mọi giao diện phần tử hỗ trợ (như HTMLSelectElement, HTMLTextareaElement) đều có cùng thuộc tính chỉ có thể đọc.

Thuộc tính disabled không áp dụng cho các phần tử inert thông thường có thể làm tâm điểm thông qua tabindex hoặc contenteditable. Chính sách này cũng không áp dụng cho phần tử <form>. Để tắt những tính năng này, bạn có thể dùng thuộc tính inert chung.

Thuộc tính inert

Khi bạn thêm thuộc tính boolean toàn cục inert vào một phần tử, phần tử đó và mọi nội dung lồng nhau sẽ bị vô hiệu hoá (không thể nhấp cũng như không thể gắn thẻ) và bị xoá khỏi cây hỗ trợ tiếp cận. Mặc dù inert có thể áp dụng cho mọi phần tử, nhưng thường được dùng cho các phần nội dung, chẳng hạn như nội dung ngoài màn hình hoặc nội dung bị ẩn.

Khi áp dụng disabled cho các thành phần điều khiển biểu mẫu, trình duyệt sẽ cung cấp kiểu mặc định và có thể được tạo kiểu bằng cách sử dụng lớp giả :disabled. Thuộc tính inert không cung cấp chỉ báo trực quan và không có lớp giả phù hợp (mặc dù bộ chọn thuộc tính [inert] khớp).

Việc sử dụng inert trên nội dung hiển thị mà không có kiểu cho biết tính chất trơ có thể dẫn đến trải nghiệm người dùng kém. Vì người dùng trình đọc màn hình không có nội dung trơ, nội dung này có thể gây nhầm lẫn khi người dùng trình đọc màn hình khi nhìn thấy nội dung trên màn hình mà các công cụ hỗ trợ tiếp cận không có. Làm cho tính năng trơ thể hiện rõ ràng thông qua CSS.

Hãy đảm bảo tiêu điểm không bao giờ chuyển sang nội dung không hiển thị. Mọi nội dung kết xuất ngoài màn hình mà không tự động xuất hiện khi được lấy làm tâm điểm đều phải được chuyển thành trơ. Nếu nội dung bị ẩn, nhưng xuất hiện khi được lấy làm tâm điểm, chẳng hạn như đường liên kết chuyển đến nội dung trên trang này, thì nội dung đó không cần được đặt ở chế độ tĩnh.

Kiểm tra kiến thức

Kiểm tra kiến thức

Kiểm tra kiến thức về sự tập trung.

Nếu không thể lấy tiêu điểm một phần tử, thì nó được mô tả là gì?

Trống.
Hãy thử lại.
Trơ.
Chính xác!
Bị ẩn.
Hãy thử lại.

Điều gì sẽ đúng nếu phần tử có thuộc tính disabled?

Ảnh sẽ không thể lấy tiêu điểm.
Chính xác!
Thông tin này sẽ không được hiển thị.
Hãy thử lại.
Nếu đó là một thành phần biểu mẫu, thì nó sẽ không được gửi.
Chính xác!