Поиск по скрытому контенту

В веб-интерфейсах часто скрывают контент, чтобы сделать их удобнее, сэкономить место на экране или повысить скорость загрузки страницы. Традиционные методы, такие как display: none или visibility: hidden, позволяют скрыть контент визуально, но они также делают его полностью недоступным для программ чтения с экрана и функций браузера, таких как "Найти на странице".

Чтобы скрыть контент, но оставить его доступным для поиска и ссылок на контент с помощью фрагментов URL и ссылок "Прокрутка до текстового фрагмента", можно использовать элемент HTML <details> или атрибут hidden="until-found". Обычно рекомендуется использовать элемент <details>, поскольку его проще внедрить и поддерживать. Однако в некоторых сложных случаях элемента <details> недостаточно и требуется hidden="until-found".

Пример:

  • Если вы хотите полностью контролировать стиль механизма показа/скрытия.
  • Если элементы управления пользовательского интерфейса, позволяющие показывать или скрывать контент, находятся в другой части DOM.
  • Если вы не хотите поддерживать скрытие контента после его показа.

Рекомендации по внедрению

Элемент <details> по умолчанию содержит текст, доступный для поиска и специальных возможностей, и не требует специальной реализации. По возможности используйте <details> вместо hidden="until-found".

Если вам нужно использовать hidden="until-found", следуйте этим инструкциям:

  1. Примените атрибут. Добавьте HTML-атрибут hidden="until-found" непосредственно к элементам, содержащим контент, который нужно скрыть.
  2. Синхронизируйте состояние интерфейса. Если в интерфейсе есть связанные состояния, которые зависят от видимости контента (например, обновляются атрибуты ARIA, переключаются классы CSS или поворачиваются значки аккордеона):
    • ОБЯЗАТЕЛЬНО добавьте прослушиватель событий для события beforematch.
    • Зарегистрируйте прослушиватель событий beforematch непосредственно в элементе, содержащем атрибут hidden="until-found". Поскольку событие всплывает, вы можете использовать делегирование событий, зарегистрировав один прослушиватель в родительском элементе (например, в контейнере вкладок), чтобы управлять несколькими скрытыми разделами одновременно.
    • Внутри прослушивателя событий выполните логику для синхронизации связанных элементов пользовательского интерфейса (например, закройте другие открытые вкладки или измените состояние переключателя).

Пример кода

Цель. Создать скрытый контейнер, контент которого остается невидимым для пользователя, пока он не выполнит поиск по слову в этом разделе.

Использование элемента <details>

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

Взаимоисключающие сведения

При работе с взаимоисключающими областями контента, такими как эксклюзивный аккордеон, используйте нативный элемент HTML <details> с общим атрибутом name.

<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>

Использование атрибута 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>

Взаимоисключающие настраиваемые сообщения о раскрытии информации

При работе с настраиваемыми взаимоисключающими областями, управляемыми внешними кнопками, убедитесь, что видна только соответствующая панель. В обработчике событий beforematch необходимо синхронизировать связанные состояния ARIA, например задать aria-expanded="true" для кнопки управления.

<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');
  });
});

Рекомендации для цели "hidden="until-found""

  • РЕКОМЕНДУЕТСЯ применять границы, поля и фоны к вложенным дочерним контейнерам, а не непосредственно к элементу с атрибутом hidden="until-found". Это предотвращает непреднамеренные сдвиги макета или визуальные остатки, пока элемент скрыт.
  • НЕ применяйте свойства CSS display: none, visibility: hidden или любые связанные с ними свойства display или visibility непосредственно к элементам с атрибутом hidden="until-found". Это нарушает работу встроенных функций и навсегда скрывает контент из индекса Google Поиска.
  • НЕ используйте hidden="until-found" для конфиденциальной информации, токенов внутренних данных или нерелевантных данных, которые не должны быть доступны через поиск.
  • НЕ используйте hidden="until-found" вместо текста, предназначенного только для программ чтения с экрана (.sr-only).

Поддержка браузеров и резервные стратегии

НЕ отказывайтесь от hidden="until-found" из-за отсутствия поддержки в браузере, поскольку преимущества специальных возможностей намного перевешивают затраты на реализацию резервного варианта.

hidden="until-found" резервное объявление

Для стандартных элементов интерфейса, таких как аккордеоны или разделы "Читать далее", используйте JavaScript, чтобы определить, поддерживается ли функция, и показать весь контент, если нет.

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.
  });
}

Если элементы интерфейса являются взаимоисключающими (например, настраиваемые эксклюзивные панели, где контент находится в одной и той же визуальной области), резервный вариант должен извлекать и показывать весь контент линейно под основной интерактивной областью, используя фрагменты якорей URL, чтобы пользователи могли переходить непосредственно к соответствующим разделам.