# CSS自定义高亮API

CSS 自定义高亮 API 提供了一种方法,可以通过使用 JavaScript 创建范围并使用 CSS 定义样式来设置文档中任意文本范围的样式。

# 基础概念

使用 CSS 自定义高亮 API 设置网页上文本范围的样式有四个步骤:

  1. 创建 Range 对象。
  2. 为这些范围创建 Highlight 对象。
  3. 使用 HighlightRegistry 进行注册。
  4. 使用 ::highlight() 伪元素定义高亮样式。

TIP

需要注意的是,设置的节点是文本节点,也就是nodeType === Node.TEXT_NODE的节点

简单示例如下

  <body>
    <style>
      div {
        color: #ccc;
      }
      ::highlight(highlight-1) {
        background-color: yellow;
        color: black;
      }
    </style>
    <div class="box">
      CSS 自定义高亮 API 提供了一种方法,可以通过使用 JavaScript 创建范围并使用
      CSS定义样式来设置文档中任意文本范围的样式。在网页上设置文本范围样式非常有用 <br />
      。例如,文本编辑类的Web 应用程序会突出显示拼写或语法错误,代码编辑器会突出显示语法错误。
    </div>
    <script>
      const box = document.querySelector('.box');
      console.log(box.childNodes);

      const range1 = new Range();
      range1.setStart(box.childNodes[0], 10);
      range1.setEnd(box.childNodes[0], 20);

      const highlight1 = new Highlight(range1);

      CSS.highlights.set('highlight-1', highlight1);

      //    CSS.highlights.delete('highlight-1');
    </script>
  </body>

# 示例

搜索文本高亮的示例

Maxime debitis hic, delectus perspiciatis laborum molestiae labore, deleniti, quam consequatur iure veniam alias voluptas nisi quo. Dolorem eaque alias, quo vel quas repudiandae architecto deserunt quidem, sapiente laudantium nulla.

Maiores odit molestias, necessitatibus doloremque dolor illum reprehenderit provident nostrum laboriosam iste, tempore perferendis! Ab porro neque esse voluptas libero necessitatibus fugiat, ex, minus atque deserunt veniam molestiae tempora? Vitae.

Dolorum facilis voluptate eaque eius similique ducimus dignissimos assumenda quos architecto. Doloremque deleniti non exercitationem rerum quam alias harum, nisi obcaecaticorporis temporibus vero sapiente voluptatum est quibusdam id ipsa.

CSS 自定义高亮 API 提供了一种方法,可以通过使用 JavaScript 创建范围并使用 CSS 定义样式来设置文档中任意文本范围的样式。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>05</title>
  </head>
  <body>
    <style>
      ::highlight(search-results) {
        background-color: #f06;
        color: white;
      }
    </style>
    <label>Search within text <input id="query" type="text" /></label>
    <article>
      <p>
        Maxime debitis hic, delectus perspiciatis laborum molestiae labore, deleniti, quam
        consequatur iure veniam alias voluptas nisi quo. Dolorem eaque alias, quo vel quas
        repudiandae architecto deserunt quidem, sapiente laudantium nulla.
      </p>
      <p>
        Maiores odit molestias, necessitatibus doloremque dolor illum reprehenderit provident
        nostrum laboriosam iste, tempore perferendis! Ab porro neque esse voluptas libero
        necessitatibus fugiat, ex, minus atque deserunt veniam molestiae tempora? Vitae.
      </p>
      <p>
        Dolorum facilis voluptate eaque eius similique ducimus dignissimos assumenda quos
        architecto. Doloremque deleniti non exercitationem rerum quam alias harum, nisi
        obcaecaticorporis temporibus vero sapiente voluptatum est quibusdam id ipsa.
      </p>
    </article>
    <script>
      const query = document.getElementById('query');
      const article = document.querySelector('article');

      // Find all text nodes in the article. We'll search within
      // these text nodes.
      const treeWalker = document.createTreeWalker(article, NodeFilter.SHOW_TEXT);
      const allTextNodes = [];
      let currentNode = treeWalker.nextNode();
      while (currentNode) {
        allTextNodes.push(currentNode);
        currentNode = treeWalker.nextNode();
      }
      console.log(allTextNodes);

      // Listen to the input event to run the search.
      query.addEventListener('input', () => {
        // If the CSS Custom Highlight API is not supported,
        // display a message and bail-out.
        if (!CSS.highlights) {
          article.textContent = 'CSS Custom Highlight API not supported.';
          return;
        }

        // Clear the HighlightRegistry to remove the
        // previous search results.
        CSS.highlights.clear();

        // Clean-up the search query and bail-out if
        // if it's empty.
        const str = query.value.trim().toLowerCase();
        if (!str) {
          return;
        }

        // Iterate over all text nodes and find matches.
        const ranges = allTextNodes
          .map(el => {
            return { el, text: el.textContent.toLowerCase() };
          })
          .map(({ text, el }) => {
            const indices = [];
            let startPos = 0;
            while (startPos < text.length) {
              const index = text.indexOf(str, startPos);
              if (index === -1) break;
              indices.push(index);
              startPos = index + str.length;
            }

            // Create a range object for each instance of
            // str we found in the text node.
            return indices.map(index => {
              const range = new Range();
              range.setStart(el, index);
              range.setEnd(el, index + str.length);
              return range;
            });
          });

        console.log(ranges);

        // Create a Highlight object for the ranges.
        const searchResultsHighlight = new Highlight(...ranges.flat());

        // Register the Highlight object in the registry.
        CSS.highlights.set('search-results', searchResultsHighlight);
      });
    </script>
  </body>
</html>

MDN文档 (opens new window)

上次更新: 4/1/2025, 9:33:10 AM