CSS Custom Highlight API 可实现无 DOM 操作、无重排重绘的全文搜索高亮,需 Chrome 105+/Edge 105+/Firefox 119+ 支持;核心是分离匹配(异步处理)与渲染(Range + ::highlight),精准定位文本节点构建 Range,唯一命名注册 Highlight,并仅用支持样式属性控制外观。

直接用 CSS Custom Highlight API 实现全文搜索高亮,确实能做到不操作 DOM、不触发重排重绘、支持异步处理——但前提是浏览器支持(Chrome 105+、Edge 105+、Firefox 119+ 已稳定启用),且 JS 逻辑设计得当。
核心思路:分离“匹配定位”与“高亮渲染”
传统高亮在搜索后立刻修改 innerHTML 或插入 span,而 CSS.highlights 的优势在于:文本内容保持原样,仅通过 Range 标记位置 + CSS 渲染叠加。因此可将耗时的字符串匹配过程完全异步化,再批量提交高亮范围。
- 用 Web Worker 或 requestIdleCallback 处理长文本正则匹配,避免阻塞主线程
- 匹配结果只记录 {node, startOffset, endOffset},不操作 DOM
- 收集完所有 Range 后,一次性创建 Highlight 并注册到 CSS.highlights
关键步骤:Range 构建必须精准对应文本节点
不能对整个容器调 setStart(container, n),必须精确落到某个 TextNode 上,否则高亮会错位或失效。
- 先用 TreeWalker 获取全部文本节点(跳过 script/style/隐藏元素)
- 遍历每个文本节点,toLowerCase() 后用 indexOf 或正则找关键词起止位置
- 对每次命中,调 range.setStart(textNode, start) 和 range.setEnd(textNode, end)
- 注意:同一关键词跨两个相邻文本节点时需拆分处理(这种情况较少,但需兜底)
注册与样式:名称唯一、伪类可控
CSS.highlights 是全局注册表,名称冲突会导致覆盖;::highlight() 只接受已注册的名称,且仅支持有限样式属性。
立即学习“前端免费学习笔记(深入)”;
- 推荐用语义化名称,如 "search-highlight-20260506" 避免复用冲突
- CSS 中只写允许的样式:background-color、color、text-decoration、text-shadow 等
- 不支持 background-image、渐变、transform,也不继承父级 font-size(需显式设置)
- 高亮可叠加:多个 ::highlight() 规则同时生效,适合协作文档多用户标记
异步优化实战建议
真正影响性能的不是高亮本身,而是匹配过程。DOM 不动 ≠ 逻辑不卡,所以重点在 JS 层调度:
- 对超长文档(如 >50KB 纯文本),把文本节点分组,每组匹配完再 requestIdleCallback 下一组
- 输入防抖后,上一次的高亮应先 clear(),再注册新 highlight,避免残留
- 若搜索词为空或无结果,直接 CSS.highlights.delete(name),不创建空 Highlight
- 移动端注意:iOS Safari 尚未支持,需降级为 mark 标签方案(可用 feature detect 自动切换)



















