是唯一传达文本强相关语义的元素,安全高亮需用 treewalker 遍历文本节点、双重转义关键词、创建 mark 元素插入 dom,并显式声明适配暗色模式与色觉障碍的 css 样式。

mark 标签不是“加个黄底”的快捷方式,它是唯一能向浏览器、读屏器和搜索引擎传达“这段文本与当前上下文强相关”的语义化元素。直接写 <mark>关键词</mark> 能渲染出高亮效果,但真实项目中必须配合转义、样式声明和 DOM 操作规范,否则大概率失效或引发 XSS。
为什么不能直接用 innerHTML.replace() 做搜索高亮
这是最常见也最危险的写法:用字符串替换整个容器的 innerHTML。它同时打开三扇门——XSS、DOM 结构破坏、HTML 解析中断。
- 用户搜
[a-z],正则没转义 →new RegExp(keyword)报错,脚本中断 - 用户搜
<script>alert(1)</script>,拼进字符串后可能执行脚本 - 原文是
<code>console.log(),替换后变成<code>console.<mark>log</mark>(),<mark></mark>被撕开,DOM 解析失败 - 图片
<img src="logo.png">中搜logo→ 变成<img src="<mark>logo</mark>.png">,图片挂掉
安全高亮必须只操作文本节点
核心是绕过字符串拼接,只在纯文本内容上做切分与替换。关键路径是:TreeWalker 遍历 → 匹配 textContent → 创建 mark 元素 → 插入 DOM。
- 用
document.createTreeWalker(element, NodeFilter.SHOW_TEXT)获取所有文本节点 - 跳过空文本或仅含空白符的节点(
node.textContent.trim() === '') - 对每个节点内容调用
replace(),但匹配前必须双重转义:
— HTML 转义:keyword.replace(/[&"'`=/]/g, c => `${c.charCodeAt(0)};`)
— 正则转义:keyword.replace(/[.*+?^${}()|[]]/g, '\$&') - 匹配后不要返回字符串,而是创建元素:
const mark = document.createElement('mark'); mark.textContent = match;,再用node.parentNode.replaceChild(mark, node)
样式必须显式声明,别信浏览器默认值
浏览器默认黄色背景在暗色模式、高对比度设置、邮件客户端、阅读模式下基本不可见。不写 CSS 就上线,等于放弃可访问性。
- 至少声明这三项:
background-color、color、padding;border-radius是加分项 - 深色模式必须手动适配:
@media (prefers-color-scheme: dark) { mark { background-color: #ffca28; color: #121212; } } - 避免写
background: none——它不会清空background-image,应写background-color: transparent或initial - 别只靠颜色区分:色觉障碍用户可能无法识别黄底,建议搭配轻微
box-shadow: inset 0 -2px 0 #007acc或加粗(注意行高)
真正容易被忽略的是中文词边界处理和大小写还原逻辑——mark 不自动感知“词”概念,搜“前端”可能命中“前后端”里的“前端”,而大小写敏感时又可能漏掉“Frontend”。这些得靠分词库或更精细的正则捕获组来补足,不是加个标签就能一劳永逸的事。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











