Стилизация текста с помощью CSS Custom Highlight API

CSS Custom Highlight API решает фундаментальную проблему: как программно выделять диапазоны текста, не засоряя DOM обёрточными элементами. Независимо от того, создаёте ли вы поисковые интерфейсы, текстовые редакторы или образовательные приложения, этот API предлагает более чистый и производительный подход по сравнению с традиционными методами на основе <mark>
или span-элементов.
Ключевые моменты
- CSS Custom Highlight API позволяет выделять текст без манипуляций с DOM
- Выделение работает через объекты Range, объекты Highlight и реестр CSS.highlights
- Производительность значительно улучшается, поскольку не происходит пересчёт макета
- Можно одновременно выделять несколько несмежных диапазонов
Что отличает CSS Custom Highlight API
Традиционное выделение текста требует изменения структуры DOM. Использование элементов <mark>
или span означает вставку узлов, запуск пересчёта макета и управление сложным HTML, когда выделения охватывают несколько элементов. CSS Custom Highlight API устраняет эти проблемы, работая с JavaScript-диапазонами и псевдоэлементом ::highlight
, сохраняя ваш DOM в первозданном виде.
API состоит из трёх основных компонентов:
- Объекты Range, которые определяют границы текста
- Объекты Highlight, которые группируют диапазоны
- Реестр CSS.highlights, который связывает выделения со стилями
Создание и стилизация текстовых диапазонов
Создание первого выделения
Начните с создания объекта Range для определения того, какой текст выделить:
const range = new Range();
const textNode = document.querySelector('p').firstChild;
range.setStart(textNode, 0);
range.setEnd(textNode, 20);
Затем создайте объект Highlight и зарегистрируйте его:
const highlight = new Highlight(range);
CSS.highlights.set('my-highlight', highlight);
Наконец, стилизуйте его с помощью псевдоэлемента ::highlight
:
::highlight(my-highlight) {
background-color: yellow;
color: black;
}
Реализация выделения результатов поиска
Вот практический пример выделения результатов поиска в вашем документе:
function highlightSearchResults(searchTerm) {
// Очищаем существующие выделения
CSS.highlights.delete('search-results');
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT
);
const ranges = [];
let node;
while (node = walker.nextNode()) {
const text = node.textContent;
const regex = new RegExp(searchTerm, 'gi');
let match;
while (match = regex.exec(text)) {
const range = new Range();
range.setStart(node, match.index);
range.setEnd(node, match.index + searchTerm.length);
ranges.push(range);
}
}
if (ranges.length > 0) {
const searchHighlight = new Highlight(...ranges);
CSS.highlights.set('search-results', searchHighlight);
}
}
Discover how at OpenReplay.com.
Продвинутые паттерны: выделения с несколькими диапазонами
Истинная мощь проявляется при работе с несколькими несмежными текстовыми диапазонами. Один объект Highlight может содержать несколько объектов Range:
// Выделяем несколько отдельных абзацев
const range1 = new Range();
range1.selectNodeContents(document.querySelector('#intro'));
const range2 = new Range();
range2.selectNodeContents(document.querySelector('#conclusion'));
const highlight = new Highlight(range1, range2);
CSS.highlights.set('important-sections', highlight);
Вы также можете одновременно управлять несколькими группами выделений:
// Различные типы выделений с отличающимися стилями
CSS.highlights.set('errors', new Highlight(...errorRanges));
CSS.highlights.set('warnings', new Highlight(...warningRanges));
CSS.highlights.set('info', new Highlight(...infoRanges));
::highlight(errors) {
background-color: #fee;
text-decoration: wavy underline red;
}
::highlight(warnings) {
background-color: #ffa;
}
::highlight(info) {
background-color: #e6f3ff;
}
Преимущества производительности и поддержка браузерами
CSS Custom Highlight API превосходит в сценариях, критичных к производительности. В отличие от манипуляций с DOM, выделения не запускают пересчёт макета и не создают дополнительную нагрузку на память от дополнительных элементов. Движок рендеринга браузера обрабатывает выделения на уровне слоя отрисовки, делая обновления удивительно быстрыми.
По состоянию на 2025 год Chrome, Edge и Safari поддерживают API, поддержка Firefox находится в разработке. Для старых браузеров реализуйте резервный вариант с определением функциональности:
if ('CSS' in window && 'highlights' in CSS) {
// Используем Custom Highlight API
const highlight = new Highlight(range);
CSS.highlights.set('fallback-safe', highlight);
} else {
// Резервный вариант с традиционным подходом
const span = document.createElement('span');
span.className = 'highlight';
range.surroundContents(span);
}
Практические советы по реализации
При реализации выделения текста в продакшене:
-
Очищайте неиспользуемые выделения для предотвращения утечек памяти:
CSS.highlights.delete('old-highlight');
-
Обрабатывайте динамический контент, обновляя диапазоны при изменении DOM:
highlight.add(newRange); highlight.delete(oldRange);
-
Используйте осмысленные имена выделений, которые описывают их назначение (например, ‘search-results’, ‘spell-check’, ‘user-annotations’)
Заключение
CSS Custom Highlight API трансформирует наш подход к выделению текста в вебе. Отделяя логику выделения от структуры DOM, он обеспечивает лучшую производительность, более чистый код и большую гибкость по сравнению с традиционными методами. Начните экспериментировать с выделением текстовых диапазонов в вашем следующем проекте — ваши пользователи (и ваш DOM) будут вам благодарны.
Часто задаваемые вопросы
Да, API может выделять текст, который охватывает несколько элементов. Объекты Range могут начинаться в одном элементе и заканчиваться в другом, что делает его идеальным для выделения фраз, пересекающих границы абзацев или span-элементов.
Выделения остаются привязанными к своим исходным объектам Range. Если DOM изменяется, вам необходимо вручную обновить или пересоздать диапазоны. API не отслеживает мутации DOM автоматически, поэтому реализуйте собственный паттерн наблюдателя для динамического контента.
Несколько выделений могут перекрывать один и тот же текстовый диапазон. Браузер применяет все соответствующие стили выделений, при этом стили, определённые позже, имеют приоритет. Вы можете контролировать визуальное наслоение через CSS-свойства, такие как background-color и opacity.
Truly understand users experience
See every user interaction, feel every frustration and track all hesitations with OpenReplay — the open-source digital experience platform. It can be self-hosted in minutes, giving you complete control over your customer data. . Check our GitHub repo and join the thousands of developers in our community..