Назад в Центр знаний
Платформа

CSS Highlight API: отрисовка и доступность

Используйте пользовательские подсветки с семантическим текстом, ограниченными диапазонами, фокусом клавиатуры и безопасным fallback.

BotBrowser Team

Документация

Нужна структурированная документация по теме Платформа?

Эта статья относится к редакционной библиотеке. Для пошаговой настройки, справки и постоянных обновлений переходите сразу в соответствующий раздел docs.

CSS Highlight API может оформлять совпадения поиска, аннотации и выделения без изменения DOM, но подсветка является представлением, а не смыслом. BotBrowser может воспроизвести принадлежащий странице fixture подсветки и проверить видимые резервные состояния; он не подтверждает речь вспомогательной технологии, намерение чтения человека или полную реализацию отрисовки браузера. Держите контракт узким: оставляйте текст в DOM, регистрируйте ограниченные диапазоны, рисуйте различимый слой и сохраняйте семантический резерв с управлением клавиатурой.

CSS Highlight API превращает текст DOM в ограниченные диапазоны и слой отрисовки, сохраняя фокус клавиатуры, принудительные цвета и резерв DOM

TL;DR

  • CSS.highlights.set('search-hit', new Highlight(range)) оформляет Range; он не добавляет текст, подписи или семантику доступности.
  • Пользовательский псевдоэлемент подсветки вроде ::highlight(search-hit) должен использовать безопасную по контрасту пару цветов и не быть единственным сигналом.
  • Храните исходный текст и объявляемый счётчик результатов в DOM; отдельно проверяйте фокус клавиатуры, выделение, принудительные цвета, масштаб и уменьшение движения.
  • Перестраивайте диапазоны после изменений содержимого, ограничивайте их число и длину и удаляйте устаревшие записи через CSS.highlights.delete(name).
  • BotBrowser может проверить состояние страницы и резерв, но статья основана на источниках и не заявляет запуск BotBrowser.

Содержание

Сохраняйте смысл в DOM

API подсветки меняет способ отрисовки существующего текста. Range указывает на уже существующие узлы, поэтому скринридеру, копированию, поиску текста и отображению без CSS нужен тот же исходный контент. Поместите счётчик результатов в область aria-live="polite", сохраните запрос в подписанном поле и покажите для аннотаций обычный список или абзац. Не кодируйте предупреждение только жёлтым фоном или пользовательским эффектом отрисовки.

API отделён от Selection API. Выделение пользователя может быть видно через ::selection; именованная пользовательская подсветка является объектом Highlight, которым владеет приложение. Дайте каждому состоянию стабильное имя, например search-hit или current-hit, и удаляйте его при пустом запросе. Имя является CSS-крючком, а не подписью для озвучивания вспомогательной технологией.

Связанную границу визуальной идентичности описывает материал управление цветом CSS и доступность дисплея: он отделяет видимый в браузере результат стиля от заявления о возможностях. Для работы с клавиатурой локаль и приватность Keyboard Layout API показывает, почему визуальная подпись не должна становиться выводом о человеке. Проверка совместимости Web Components добавляет матрицу, разделяющую обнаружение функции и обещание читателю.

Регистрируйте ограниченные диапазоны

Создавайте диапазоны из отрисованных текстовых узлов, а не из ненадёжной HTML-строки. Простой fixture обходит текстовые узлы, ищет запрос с приведением регистра и вызывает range.setStart() и range.setEnd() для каждого совпадения. Ограничьте MAX_HIGHLIGHTS и MAX_MATCH_CHARS; страница должна оставаться отзывчивой, даже если запрос совпадает с тысячами слов.

const MAX_HIGHLIGHTS = 100;
const MAX_MATCH_CHARS = 120;

function showMatches(root, query) {
  CSS.highlights.delete('search-hit');
  if (!query || !window.Highlight) return 0;
  const ranges = [];
  for (const node of root.querySelectorAll('[data-search-text]')) {
    const text = node.textContent || '';
    let offset = 0;
    while (offset < text.length && ranges.length < MAX_HIGHLIGHTS) {
      const start = text.toLocaleLowerCase().indexOf(query.toLocaleLowerCase(), offset);
      if (start < 0) break;
      if (query.length <= MAX_MATCH_CHARS) {
        const range = new Range();
        range.setStart(node.firstChild, start);
        range.setEnd(node.firstChild, start + query.length);
        ranges.push(range);
      }
      offset = start + Math.max(query.length, 1);
    }
  }
  CSS.highlights.set('search-hit', new Highlight(...ranges));
  return ranges.length;
}

Точный fixture зависит от границ текстовых узлов; рабочий код должен безопасно обрабатывать вложенные узлы и пустой firstChild. Пересчитывайте диапазоны после отрисовки, локализации, фильтрации или переработки виртуального списка. Диапазон, указывающий на удалённое содержимое, является устаревшим состоянием, а не причиной сохранять старый объект подсветки.

Рисуйте видимый и доступный слой

Используйте псевдоэлемент ::highlight(search-hit) для именованного слоя и держите объявления небольшими. Стилизация CSS Highlight API намеренно ограничена по сравнению с обычными элементами; браузер может игнорировать неподдерживаемые свойства. Выберите цвет текста и фона, соответствующие цели контраста продукта, и добавьте в интерфейс сигнал не через цвет: контур, значок или счётчик результатов.

::highlight(search-hit) {
  color: #111827;
  background-color: #fde68a;
  text-decoration: underline 0.12em solid #92400e;
}

@media (forced-colors: active) {
  ::highlight(search-hit) {
    color: CanvasText;
    background-color: Highlight;
    text-decoration: underline;
  }
}

Не предполагайте, что пользовательская подсветка одинаково рисуется во всех движках и встроенных контекстах. Проверьте наличие CSS.highlights, Highlight и нужного селектора, а при отсутствии любой предпосылки покажите резервный класс или встроенный маркер. Видимый в браузере результат отрисовки не доказывает, что скринридер объявит «совпадение» или режим высокой контрастности сохранит выбранные цвета.

Обрабатывайте выбор, фокус и резервный режим

Поиск должен переводить фокус на настоящий элемент результата, а не на нарисованный диапазон. Добавьте кнопки «Назад» и «Далее» с доступным именем, сохраняйте запрос в поле и прокручивайте выбранный результат в область видимости, не запирая фокус клавиатуры. Если пользователь выделяет текст, не заменяйте ::selection подсветкой поиска: эти слои выражают разные состояния.

Если подсветки не поддерживаются, добавьте временный элемент mark или CSS-класс вокруг доверенного текстового узла и покажите тот же счётчик и навигацию. Удаляйте этот резерв перед новым запросом, чтобы вложенные оболочки не накапливались. Для аннотаций только для чтения соседняя заметка с aria-describedby надёжнее цветовой заплатки, исчезающей при печати или в режиме принудительных цветов.

Проверяйте масштаб 200%, интервалы текста, навигацию только клавиатурой, prefers-reduced-motion и скринридер. Подсветка не должна закрывать контуры фокуса, обрезать нижние выносные элементы или создавать мигание для каждого результата. Если запрос пуст или совпадений нет, очистите именованную подсветку и объявите «0 результатов» в live region.

Классифицируйте результаты таблицей решений

Наблюдаемая стадияЧто она устанавливаетБезопасное следующее действие
Нет CSS.highlights или HighlightВ этом контексте нельзя начать подсветкуИспользовать mark или обычный текст и сохранить навигацию
API есть, запрос пустНет диапазона для отрисовкиУдалить search-hit, объявить очистку и оставить фокус
Диапазоны созданы, отрисовка виднаСтраница применила видимый слойПроверить контраст, фокус, принудительные цвета и текст
Содержимое или локаль изменилисьСтарые смещения могут быть устаревшимиПерестроить диапазоны и удалить старый объект
Совпадений больше 100Fixture достиг ограниченной нагрузкиПоказать предел и предложить сузить поиск
Принудительные цвета или печать иныеПользовательский агент изменил представлениеСохранить DOM-результат и сигнал, не зависящий от цвета

Каждая строка описывает наблюдаемое состояние, а не универсальную гарантию. Записывайте видимое состояние, длину запроса, число диапазонов и резервную ветвь; не сохраняйте весь документ и не выводите намерения читателя.

Контрольная точкаЗаписьЧто нельзя заключать
Проверка APICSS.highlights=true, Highlight=trueЧто скринридер озвучит слой
Жизненный циклrangeCount=3, длина и узлыЧто текст связан с личностью
Резервfallback=mark и причинаЧто нарушена вся система доступности
ФокусfocusTarget=result-2 и порядок клавишНамерение пользователя
Очисткастарый highlight удалёнУдаление удалённого состояния
ПроверкаМинимальная записьЧего нельзя заключать
Совместимость APIwindow.CSS, CSS.highlights, window.HighlightЧто поддерживаются все CSS-свойства
Лимиты запросаMAX_HIGHLIGHTS=100, MAX_MATCH_CHARS=120Что безопасно хранить весь документ
Текущий диапазонисходный узел и rangeCountЧто текст связан с личностью
ФокусfocusTarget=result-2Что человек хочет читать этот результат
Визуальный режимобычный, принудительные цвета или печатьЧто физический экран даёт те же цвета
Очисткаимя удалено перед новым рендерингомЧто удалено удалённое состояние

Возможности и ограничения BotBrowser

BotBrowser может выполнить разрешённый fixture страницы и проверить счётчик DOM, число диапазонов и ветвь резервного режима. Он не может подтвердить речь программы чтения с экрана или гарантировать одинаковую отрисовку ::highlight() во всех движках.

BotBrowser может повторить разрешённый сценарий с диапазонами Highlight, стилем ::highlight() и видимым резервом; эта статья не заявляет запуск BotBrowser и не подтверждает речь скринридера или восприятие цвета.

{
  "api": "CSS.highlights",
  "highlightName": "search-hit",
  "rangeCount": 3,
  "maxHighlights": 100,
  "domResultText": "3 matches",
  "assistiveTechnologySpeech": "not-asserted"
}

Повторяйте fixture после выпуска браузера, изменения локализации, виртуального списка или токена контраста. Сравнивайте первое видимое расхождение и сохраняйте резерв DOM в записи приёмки.

Практическая последовательность проверки

Начните с семантического пути до проверки пикселей. Отправьте запрос с отключённым search-hit и убедитесь, что счётчик, заголовки и текст остаются понятными. Затем включите пользовательскую подсветку и сравните тот же диапазон при масштабе 100%, 200% и 400%. Такой порядок выявляет регрессию, когда аккуратный визуальный слой скрывает недоступный с клавиатуры список результатов.

Меняйте одну переменную за раз: замените текст переводом, переработайте элемент списка и включите forced-colors: active. Корректная реализация удаляет старый Highlight, создаёт диапазоны для нового текстового узла и сохраняет live-счётчик. Записывайте первое расхождение, а не объявляйте итоговый снимок вердиктом браузера.

Источники

Заключение

Используйте пользовательскую отрисовку CSS Highlight API, чтобы выделять текст с уже существующим смыслом. Ограничивайте и перестраивайте диапазоны, храните статус и навигацию в DOM и давайте безопасную по контрасту альтернативу без цвета. BotBrowser может воспроизвести состояние страницы, но запуск не заявлен; результат не доказывает озвучивание скринридером или понимание пользователя.

#CSS Highlight API#CSS Custom Highlight API#Accessibility#CSS Painting#BotBrowser

Эта статья входит в руководство: Поверхности веб-платформы: карта проверки

Переведите BotBrowser из исследований в продакшн

Используйте эти руководства, чтобы понять модель, а затем перейти к кроссплатформенной валидации, изолированным контекстам и масштабируемому браузерному развертыванию.