CSS Custom Highlight API
CSS 自定义高亮 API 提供了一种机制,可以通过 JavaScript 创建任意文本范围,并使用 CSS 为其着色。
概念与用法
为网页上的文本范围着色非常有用。例如,文本编辑 Web 应用会高亮拼写或语法错误,代码编辑器会高亮语法错误。
CSS 自定义高亮 API 扩展了其他高亮伪元素的概念,例如 ::selection、::spelling-error、::grammar-error 和 ::target-text,它提供了一种创建和样式化任意 Range 对象的方法,而不局限于浏览器定义的范围。
使用 CSS 自定义高亮 API,您可以以编程方式创建文本范围并对其进行高亮,而不会影响页面的 DOM 结构。
使用 CSS 自定义高亮 API 为网页上的文本范围着色有四个步骤:
- 创建
Range对象。 - 为这些范围创建
Highlight对象。 - 使用
HighlightRegistry注册高亮。 - 使用
::highlight()伪元素为高亮着色。
创建范围
第一步是通过在 JavaScript 中创建 Range 对象来定义您想要着色的文本范围。例如:
const parentNode = document.getElementById("foo");
const range1 = new Range();
range1.setStart(parentNode, 10);
range1.setEnd(parentNode, 20);
const range2 = new Range();
range2.setStart(parentNode, 40);
range2.setEnd(parentNode, 60);
创建高亮
第二步是为您的文本范围实例化 Highlight 对象。
多个范围可以关联到同一个高亮。如果您想以相同的方式高亮多个文本片段,则需要创建一个高亮,并用相应的范围对其进行初始化。
const highlight = new Highlight(range1, range2);
但是您也可以根据需要创建任意数量的高亮。例如,如果您正在构建一个协作式文本编辑器,每个用户都有不同的文本颜色,那么您可以为每个用户创建一个高亮,如下面的代码片段所示:
const user1Highlight = new Highlight(user1Range1, user1Range2);
const user2Highlight = new Highlight(user2Range1, user2Range2, user2Range3);
每个高亮都可以有不同的样式。
注册高亮
创建高亮后,使用可用的 CSS.highlights HighlightRegistry 来注册它们。
注册表是一个类似 Map 的对象,用于按名称注册高亮,如下所示:
CSS.highlights.set("user-1-highlight", user1Highlight);
CSS.highlights.set("user-2-highlight", user2Highlight);
在上面的代码片段中,user-1-highlight 和 user-2-highlight 字符串是自定义标识符,可以在 CSS 中用于将样式应用于已注册的高亮。
您可以在注册表中注册任意数量的高亮,还可以删除高亮并清空整个注册表。
// Remove a single highlight from the registry.
CSS.highlights.delete("user-1-highlight");
// Clear the registry.
CSS.highlights.clear();
样式高亮
最后一步是为已注册的高亮着色。这可以通过使用 ::highlight() 伪元素来完成。例如,为上一步注册的 user-1-highlight 高亮着色:
::highlight(user-1-highlight) {
background-color: yellow;
color: black;
}
接口
Highlight-
此接口用于表示要在文档上着色的一组范围。
HighlightRegistry-
可通过
CSS.highlights访问,这个类似Map的对象用于使用自定义标识符注册高亮。
示例
高亮搜索结果
此示例显示了如何使用 CSS 自定义高亮 API 来高亮搜索结果。
HTML
下面的 HTML 代码片段定义了一个搜索字段和一个包含几段文本的文章:
<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 obcaecati corporis temporibus vero sapiente voluptatum est
quibusdam id ipsa.
</p>
</article>
JavaScript
JavaScript 用于监听搜索字段的 input 事件。当事件触发时,代码会在文章文本中查找与输入文本匹配的内容。然后,它会为匹配项创建范围,并使用 CSS 自定义高亮 API 创建和注册一个 search-results 高亮对象。
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();
}
// 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) => ({ 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;
});
});
// 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);
});
CSS
最后,在 CSS 中使用 ::highlight() 伪元素来为高亮着色。
::highlight(search-results) {
background-color: #ff0066;
color: white;
}
结果
结果如下所示。在搜索字段中输入文本,即可高亮文章中的匹配项。
规范
| 规范 |
|---|
| CSS 自定义高亮 API 模块级别 1 |
浏览器兼容性
api.Highlight
加载中…
api.HighlightRegistry
加载中…
css.selectors.highlight
加载中…
另见
- CSS 自定义高亮 API:Web 上高亮文本范围的未来
- HTML
contentEditable属性 - CSS
伪元素 - CSS 自定义高亮 API 模块