12k
All articles

使用 CSS Custom Highlight API 为文本添加样式

通过 CSS Custom Highlight API 为文本范围添加样式,无需 DOM 包装元素,可提升搜索界面、文本编辑器和注释工具的性能。

OpenReplay Team
OpenReplay Team
使用 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 ranges 和 ::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);
  }
}

高级模式:多范围高亮

当处理多个非连续文本范围时,真正的威力才会显现。单个 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);
}

实际实现技巧

在生产环境中实现文本高亮时:

  1. 清理未使用的高亮以防止内存泄漏:

    CSS.highlights.delete('old-highlight');
  2. 处理动态内容,在 DOM 变化时更新范围:

    highlight.add(newRange);
    highlight.delete(oldRange);
  3. 使用有意义的高亮名称来描述其用途(例如 ‘search-results’、‘spell-check’、‘user-annotations’)

结论

CSS Custom Highlight API 改变了我们在 Web 上处理文本高亮的方式。通过将高亮逻辑与 DOM 结构分离,它提供了比传统方法更好的性能、更清洁的代码和更大的灵活性。开始在您的下一个项目中尝试高亮文本范围——您的用户(和您的 DOM)会感谢您的。

常见问题

CSS Custom Highlight API 能否高亮跨越不同 HTML 元素的文本?

是的,该 API 可以高亮跨越多个元素的文本。Range 对象可以在一个元素中开始,在另一个元素中结束,这使其非常适合高亮跨越段落或 span 边界的短语。

当 DOM 内容发生变化时,高亮会发生什么?

高亮仍然附着在其原始 Range 对象上。如果 DOM 发生变化,您需要手动更新或重新创建范围。该 API 不会自动跟踪 DOM 变化,因此需要为动态内容实现自己的观察者模式。

CSS Custom Highlight API 如何处理重叠的高亮?

多个高亮可以重叠同一文本范围。浏览器会应用所有匹配的高亮样式,后定义的样式具有优先权。您可以通过 CSS 属性(如 background-color 和 opacity)控制视觉层叠。

Digital experience platform

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.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.