Tìm nội dung bị ẩn

Giao diện web thường ẩn nội dung bị ẩn khỏi chế độ xem để cải thiện trải nghiệm người dùng, tiết kiệm không gian màn hình hoặc tăng hiệu suất trang. Các phương thức truyền thống như display: none hoặc visibility: hidden có tác dụng ẩn nội dung một cách trực quan, nhưng cũng khiến trình đọc màn hình và các tính năng của trình duyệt như "Tìm trong trang" hoàn toàn không truy cập được nội dung đó.

Để ẩn nội dung về mặt hình ảnh nhưng vẫn cho phép người dùng tìm kiếm và liên kết sâu đến nội dung đó thông qua các phân mảnh URL và đường liên kết "Cuộn đến phân mảnh văn bản", bạn có thể sử dụng phần tử HTML <details> hoặc thuộc tính hidden="until-found". Nhìn chung, bạn nên sử dụng phần tử <details> vì phần tử này dễ triển khai và duy trì hơn, nhưng có một số trường hợp phức tạp hơn mà <details> không đủ và cần có hidden="until-found".

Ví dụ:

  • Nếu bạn muốn có toàn quyền kiểm soát kiểu của cơ chế hiện/ẩn.
  • Nếu các thành phần điều khiển trên giao diện người dùng để hiện/ẩn nội dung nằm ở một phần khác của DOM.
  • Nếu bạn không muốn hỗ trợ việc ẩn nội dung sau khi nội dung đó xuất hiện.

Cách triển khai

Theo mặc định, phần tử <details> có văn bản có thể tìm kiếm và hỗ trợ tiếp cận, đồng thời không cần triển khai đặc biệt. Ưu tiên sử dụng <details> thay vì hidden="until-found" nếu có thể.

Nếu bạn cần sử dụng hidden="until-found", hãy làm theo hướng dẫn sau:

  1. Áp dụng thuộc tính: Thêm trực tiếp thuộc tính HTML hidden="until-found" vào các phần tử chứa nội dung cần ẩn khỏi chế độ xem.
  2. Đồng bộ hoá trạng thái giao diện người dùng: Nếu giao diện có các trạng thái liên quan phụ thuộc vào chế độ hiển thị của nội dung (ví dụ: cập nhật thuộc tính ARIA, bật/tắt các lớp CSS mở/đóng hoặc xoay biểu tượng accordion):
    • Bạn PHẢI thêm trình nghe sự kiện cho sự kiện beforematch.
    • Đăng ký trình nghe sự kiện beforematch ngay trên phần tử mang thuộc tính hidden="until-found". Vì sự kiện này nổi bọt, nên bạn cũng có thể sử dụng tính năng uỷ quyền sự kiện bằng cách đăng ký một trình nghe duy nhất trên một phần tử mẹ (chẳng hạn như vùng chứa thẻ) để quản lý nhiều phần bị ẩn cùng một lúc.
    • Bên trong trình nghe sự kiện, hãy thực thi logic để đồng bộ hoá các phần tử trên giao diện người dùng có liên quan (chẳng hạn như đóng các thẻ đang mở khác hoặc thay đổi trạng thái của nút bật tắt).

Mã mẫu

Mục tiêu: Hiển thị một vùng chứa ẩn, trong đó nội dung vẫn ẩn đối với người dùng cho đến khi họ tìm kiếm một từ trong phần đó.

Sử dụng phần tử <details>

<details>
  <summary>Click to expand</summary>
  <p>This content is visually hidden.</p>
</details>

Thông tin công bố loại trừ lẫn nhau

Khi xử lý các vùng nội dung loại trừ lẫn nhau, chẳng hạn như accordion độc quyền, hãy sử dụng phần tử HTML <details> gốc có thuộc tính name dùng chung.

<div class="accordion-group">
  <!-- The name attribute creates an exclusive disclosure group -->
  <details class="disclosure" name="my-accordion">
    <summary>Section 1</summary>
    <p>Section 1 content</p>
  </details>

  <details class="disclosure" name="my-accordion" open>
    <summary>Section 2</summary>
    <p>Section 2 content</p>
  </details>

  <details class="disclosure" name="my-accordion">
    <summary>Section 3</summary>
    <p>Section 3 content</p>
  </details>
</div>

Sử dụng thuộc tính hidden="until-found"

<!-- The browser automatically removes hidden="until-found" upon a search match -->
<div class="hidden-container" hidden="until-found">
  <p>This content is visually hidden.</p>
</div>

Thông tin công bố loại trừ lẫn nhau tuỳ chỉnh

Khi xử lý các vùng loại trừ lẫn nhau tuỳ chỉnh do các nút bên ngoài kiểm soát, hãy đảm bảo chỉ có bảng điều khiển phù hợp mới hiển thị. Trong trình xử lý sự kiện beforematch, bạn PHẢI đồng bộ hoá các trạng thái ARIA có liên quan, chẳng hạn như đặt aria-expanded="true" trên nút điều khiển.

<div class="custom-accordion">
  <div class="controls">
    <button aria-expanded="true" aria-controls="panel-1" id="btn-1">Section 1</button>
    <button aria-expanded="false" aria-controls="panel-2" id="btn-2">Section 2</button>
  </div>

  <div id="panel-1" class="panel">
    <p>Section 1 content (visible)</p>
  </div>

  <div id="panel-2" class="panel" hidden="until-found">
    <p>Section 2 content (hidden)</p>
  </div>
</div>
const accordion = document.querySelector('.custom-accordion');

accordion.addEventListener('beforematch', (e) => {
  // Hide all panels and synchronize button states before the browser reveals the matched panel
  accordion.querySelectorAll('.panel').forEach((panel) => {
    if (panel !== e.target) {
      panel.hidden = 'until-found';
    }
  });
  accordion.querySelectorAll('button').forEach((btn) => {
    const controls = btn.getAttribute('aria-controls');
    btn.setAttribute('aria-expanded', controls === e.target.id ? 'true' : 'false');
  });
});

Các phương pháp hay nhất cho hidden="until-found"

  • NÊN áp dụng đường viền, khoảng đệm và nền cho các trình bao bọc con lồng nhau thay vì áp dụng trực tiếp cho phần tử có thuộc tính hidden="until-found". Điều này giúp ngăn chặn sự thay đổi bố cục ngoài ý muốn hoặc tàn dư hình ảnh trong khi phần tử bị ẩn.
  • KHÔNG áp dụng display: none, visibility: hidden hoặc bất kỳ thuộc tính CSS display hoặc visibility nào liên quan trực tiếp cho các phần tử có thuộc tính hidden="until-found". Điều này sẽ phá vỡ chức năng gốc và ẩn vĩnh viễn nội dung khỏi chỉ mục của Tìm kiếm.
  • KHÔNG sử dụng hidden="until-found" cho thông tin nhạy cảm, mã thông báo dữ liệu nội bộ hoặc dữ liệu không liên quan mà không nên hiển thị thông qua kết quả tìm kiếm.
  • KHÔNG sử dụng hidden="until-found" để thay thế cho văn bản "chỉ dành cho trình đọc màn hình" (.sr-only).

Hỗ trợ trình duyệt và chiến lược dự phòng

KHÔNG tránh sử dụng hidden="until-found" vì trình duyệt không hỗ trợ, vì lợi ích hỗ trợ tiếp cận của nó vượt xa chi phí triển khai phương án dự phòng.

Dự phòng hidden="until-found"

Đối với các phần tử trên giao diện người dùng chuẩn như danh sách xếp dọc hoặc phần "Đọc thêm", hãy sử dụng JavaScript để phát hiện tính năng và hiển thị tất cả nội dung nếu tính năng đó không được hỗ trợ.

if (!('onbeforematch' in HTMLElement.prototype)) {
  // Expand all hidden content for unsupported browsers
  document.querySelectorAll('[hidden="until-found"]').forEach((el) => {
    el.removeAttribute('hidden');
    // MANDATORY: also update any aria references to this element.
  });
}

Đối với các mô hình giao diện người dùng loại trừ lẫn nhau (như bảng điều khiển riêng tuỳ chỉnh, nơi nội dung có cùng một vùng hình ảnh), phương án dự phòng phải trích xuất và hiển thị tất cả nội dung theo tuyến tính bên dưới khu vực tương tác chính, sử dụng các đoạn neo URL để cho phép người dùng chuyển thẳng đến các phần tương ứng.