Sửa đổi thứ tự DOM bằng chỉ mục thẻ

Dave Gash
Dave Gash
Meggin Kearney
Meggin Kearney
Alexandra Klepper
Alexandra Klepper

Thứ tự thẻ mặc định do vị trí DOM của các phần tử HTML ngữ nghĩa cung cấp rất thuận tiện, nhưng có thể đôi khi bạn cần sửa đổi thứ tự thẻ. Lý tưởng nhất là di chuyển các phần tử trong HTML, nhưng có thể không khả thi. Trong những trường hợp này, bạn có thể dùng thuộc tính HTML tabindex để đặt rõ ràng vị trí thẻ của một phần tử.

Hỗ trợ trình duyệt

  • 1
  • 12
  • 1,5
  • ≤4

Nguồn

tabindex có thể được áp dụng cho bất kỳ phần tử nào, mặc dù không nhất thiết hữu ích trên mọi phần tử và có một loạt các giá trị số nguyên. Với tabindex, bạn có thể chỉ định thứ tự rõ ràng cho các phần tử trang có thể làm tâm điểm, chèn một phần tử không thể làm tâm điểm vào thứ tự thẻ và xoá các phần tử khỏi thứ tự thẻ. Ví dụ:

tabindex="0": Chèn một phần tử vào thứ tự thẻ tự nhiên. Bạn có thể lấy tiêu điểm phần tử bằng cách nhấn phím Tab. Bạn có thể lấy tiêu điểm phần tử này bằng cách gọi phương thức focus().

tabindex="-1": Xoá một phần tử khỏi thứ tự thẻ thông thường, nhưng bạn vẫn có thể lấy phần tử đó làm tâm điểm bằng cách gọi phương thức focus()

tabindex="5": Bất kỳ chỉ mục thẻ nào lớn hơn 0 sẽ đưa phần tử đó lên trước thứ tự thẻ thông thường. Nếu có nhiều phần tử có chỉ mục thẻ lớn hơn 0, thì thứ tự thẻ sẽ bắt đầu từ giá trị thấp nhất lớn hơn 0 và tăng dần lên. Việc sử dụng chỉ mục thẻ lớn hơn 0 bị coi là phản mẫu.

Điều này đặc biệt đúng đối với các phần tử không đầu vào như tiêu đề, hình ảnh hoặc tiêu đề bài viết. Nếu có thể, tốt nhất là bạn nên sắp xếp mã nguồn để trình tự DOM cung cấp một thứ tự thẻ logic. Nếu bạn sử dụng tabindex, hãy chỉ sử dụng các thành phần điều khiển tương tác tuỳ chỉnh như nút, thẻ, trình đơn thả xuống và trường văn bản; tức là các phần tử mà người dùng có thể muốn cung cấp dữ liệu đầu vào.

Chỉ thêm tabindex vào nội dung mang tính tương tác. Ngay cả khi nội dung quan trọng, chẳng hạn như hình ảnh chính, người dùng trình đọc màn hình vẫn có thể hiểu được nội dung đó mà không cần thêm tiêu điểm.

Quản lý tiêu điểm ở cấp trang

Đôi khi, tabindex là cần thiết để mang lại trải nghiệm người dùng liền mạch. Ví dụ: nếu bạn tạo một trang mạnh mẽ với nhiều phần nội dung, trong đó không phải tất cả nội dung đều hiển thị cùng một lúc. Tức là đường liên kết điều hướng sẽ thay đổi nội dung hiển thị mà không cần làm mới trang.

Trong trường hợp này, hãy xác định vùng nội dung đã chọn và cung cấp tabindex cho -1, đồng thời gọi phương thức focus. Điều này đảm bảo nội dung không xuất hiện theo thứ tự thẻ thông thường. Kỹ thuật này được gọi là quản lý tiêu điểm, giúp giữ cho ngữ cảnh mà người dùng nhận thấy đồng bộ với nội dung hình ảnh của trang web.

Quản lý tiêu điểm trong thành phần

Trong một số trường hợp, bạn cũng phải quản lý tâm điểm ở cấp độ điều khiển, chẳng hạn như với các thành phần tuỳ chỉnh.

Ví dụ: phần tử select có thể nhận tiêu điểm cơ bản. Tuy nhiên, sau khi lấy tiêu điểm ở đó, bạn có thể dùng các phím mũi tên để hiện thêm các tuỳ chọn có thể chọn. Nếu tạo một phần tử select tuỳ chỉnh, bạn cần sao chép hành vi đó để người dùng bàn phím vẫn có thể tương tác với chế độ điều khiển của bạn.

Nếu biết được hành vi bàn phím nào cần triển khai thì bạn có thể gặp khó khăn. Hướng dẫn Thực hành soạn thảo ứng dụng Internet đa dạng thức có thể truy cập (ARIA) liệt kê các loại thành phần và những loại thao tác trên bàn phím mà những thành phần đó hỗ trợ.

Có thể bạn đang làm việc trên Phần tử tuỳ chỉnh giống với một tập hợp các nút chọn, nhưng với giao diện và hành vi riêng.

<radio-group>
    <radio-button>Water</radio-button>
    <radio-button>Coffee</radio-button>
    <radio-button>Tea</radio-button>
    <radio-button>Cola</radio-button>
    <radio-button>Ginger Ale</radio-button>
</radio-group>

Để xác định xem họ cần hỗ trợ bàn phím nào, hãy xem hướng dẫn về Phương pháp ghi nhận quyền tác giả ARIA. Phần 2 chứa danh sách các mẫu thiết kế, trong đó có bảng đặc điểm cho nhóm radio. Đây là thành phần hiện có phù hợp nhất với phần tử mới của bạn.

Một trong những hành vi phổ biến của bàn phím cần được hỗ trợ là các phím mũi tên lên/xuống/trái/phải. Để thêm hành vi này vào thành phần mới, chúng tôi sử dụng kỹ thuật có tên là lưu chỉ mục thẻ.

Việc lưu chỉ mục thẻ hoạt động bằng cách đặt tabindex thành -1 cho tất cả phần tử con, ngoại trừ phần tử con đang hoạt động.

<radio-group>
  <radio-button tabindex="0">Water</radio-button>
  <radio-button tabindex="-1">Coffee</radio-button>
  <radio-button tabindex="-1">Tea</radio-button>
  <radio-button tabindex="-1">Cola</radio-button>
  <radio-button tabindex="-1">Ginger Ale</radio-button>
</radio-group>

Thành phần này sử dụng trình nghe sự kiện bàn phím để xác định phím mà người dùng nhấn. Khi điều này xảy ra, thành phần này sẽ đặt tabindex của thành phần con được lấy tiêu điểm trước đó thành -1, đặt tabindex của thành phần con được lấy làm tâm điểm thành 0 và gọi phương thức lấy tiêu điểm trên đó.

<radio-group>
    <!-- Assuming the user pressed the down arrow, we'll focus the next available child -->
    <radio-button tabindex="-1">Water</radio-button>
    <radio-button tabindex="0">Coffee</radio-button> // call .focus() on this element
    <radio-button tabindex="-1">Tea</radio-button>
    <radio-button tabindex="-1">Cola</radio-button>
    <radio-button tabindex="-1">Ginger Ale</radio-button>
</radio-group>

Khi người dùng đến con cuối cùng (hoặc đầu tiên, tuỳ thuộc vào hướng họ đang di chuyển tiêu điểm), tiêu điểm sẽ lặp lại xung quanh thành phần con đầu tiên (hoặc cuối cùng).

Hãy thử ví dụ sau đây. Kiểm tra phần tử trong DevTools để quan sát chỉ mục thẻ chuyển từ đài phát này sang đài phát tiếp theo.

Mô-đun và bẫy bàn phím

Tốt nhất là bạn nên tránh quản lý tiêu điểm theo cách thủ công vì việc này có thể dẫn đến các tình huống phức tạp. Ví dụ: một tiện ích tự động hoàn thành cố gắng quản lý tiêu điểm và ghi lại hành vi của thẻ, nhưng ngăn người dùng rời khỏi tiện ích đó cho đến khi hoàn tất. Đây được gọi là bẫy bàn phím và có thể gây khó chịu cho người dùng.

Mục 2.1.2 của WCAG nêu rõ rằng tiêu điểm bàn phím không bao giờ được khoá hoặc mắc kẹt ở một phần tử trang cụ thể. Người dùng phải có thể di chuyển đến và từ tất cả các phần tử của trang chỉ bằng bàn phím.

Trường hợp ngoại lệ của quy tắc này là phương thức. Tuy nhiên, bạn vẫn nên tránh sử dụng tabindex khi tạo một cửa sổ phụ. Với inert, bạn có thể đảm bảo rằng người dùng không thể vô tình tương tác với một phần tử (một bẫy bàn phím có chủ ý). Sử dụng phần tử <dialog> (ở chế độ trơ theo mặc định) để tạo một phương thức cho người dùng trong khi chặn các lượt nhấp và thẻ bên ngoài phương thức đó. Điều này cho phép người dùng tập trung vào một lựa chọn bắt buộc.