mark是唯一语义正确、可访问且被搜索引擎识别的高亮方式;直接innerhtml.replace()会导致xss、dom损坏及结构错乱,安全做法须用treewalker遍历文本节点,结合escapehtml、matchall和range.surroundcontents()实现。

mark 是唯一语义正确、可访问且被搜索引擎识别的高亮方式,不是“加个黄底”的快捷样式开关。用错场景或忽略安全与样式声明,高亮会失效、被读屏器跳过,甚至引入 XSS 风险。
为什么不能直接 innerHTML.replace() 包裹关键词
常见错误是写 element.innerHTML = text.replace(keyword, '<mark>$&</mark>');。这看似简单,但实际埋了三个雷:
- 如果
keyword来自 URL 或用户输入(比如q=React<script>alert(1)</script>),拼进字符串后执行,直接触发 XSS -
keyword含&、、<code>"等字符时,innerHTML解析失败,DOM 结构断裂 - 正则全局匹配不区分上下文,
/a/g会把 “apple”、“banana” 里所有 a 都高亮,而非仅完整匹配项
安全高亮必须用 DOM 方法组装节点
核心是绕过字符串拼接,用原生 API 控制文本节点和 mark 元素的生成顺序:
- 先对关键词调用
escapeHtml(keyword)转义(处理&、、<code>"等) - 用
textContent.split()切分原始文本,避免正则污染 - 遍历每个切片:匹配项用
document.createElement('mark')+textContent创建,非匹配项用document.createTextNode() - 清空目标容器子节点,再逐个
appendChild()插入
这样既保语义,又防 XSS,还能精准控制高亮边界。
mark 样式必须显式声明,不能依赖浏览器默认
旧版 Safari 忽略 mark 默认背景;Windows 高对比度模式下黄底变纯黑;深色主题中默认黄底黑字对比度不达标(AA 不合格)。生产环境务必写死关键样式:
mark {
background-color: #ffeb3b;
color: #212121;
padding: 0.1em 0.3em;
border-radius: 3px;
}
@media (prefers-color-scheme: dark) {
mark {
background-color: #ffca28;
color: #121212;
}
}
注意:background: none 不等于清空背景——它漏掉 background-image 等隐式值,应写 background-color: transparent 或明确设为 initial。
mark 只适用于上下文相关高亮,别当 strong 用
mark 的语义是“当前上下文中的相关标记”,不是“重要”或“强调”。以下场景才该用:
- 搜索结果页中动态包裹用户输入的关键词(如用户搜 “fetch”,页面中所有独立出现的 “fetch” 文本)
- 文档引用片段中标出与当前段落强相关的术语(如 “请检查
package.json中的 dependencies 字段”) - 代码示例中突出显示被修改/新增的行内部分(如
const value = <mark>42</mark>;),且需辅助技术识别为“上下文标记”
按钮文案写 <mark>立即购买</mark>、整段警告文字套 mark、或在无上下文 banner 里用它——这些都该换 strong 或 CSS 类。滥用会让语义失效,反而损害可访问性。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











