应使用语义正确的 <mark> 标签高亮搜索匹配词,而非 <span> 或 <strong>;需显式设置样式适配深色模式与高对比度模式;动态插入时须防 XSS、DOM 解析错误及嵌套非法结构,严格按长度降序匹配并逐文本节点处理。

重点标记该用 <mark> 而不是 <span> 或 <strong>
语义错了,后续所有样式、读屏器播报、SEO 提取都会偏移。比如搜索页里用户搜“CSS Grid”,<mark>CSS Grid</mark> 明确告诉浏览器“这是上下文强相关片段”;而 <span class="highlight"> 只是视觉装饰,读屏器不提示,搜索引擎也不识别其特殊性。<strong> 则表达“重要性”,适用于警告、结论等,不是“高亮匹配词”。
直接写 <mark> 会出问题?默认样式不可靠
别信浏览器黄色背景能直接上线。Windows 高对比度模式下它可能变纯黑;Safari 旧版本(≤16.4)压根不渲染背景;深色主题中默认黄底黑字对比度仅 1.8:1,远低于 WCAG AA 要求的 4.5:1。
- 必须显式声明
background-color和color,例如:mark { background-color: #ffeb3b; color: #212121; } - 加
padding: 0.1em 0.2em避免文字贴边,border-radius: 2px微调圆角 - 暗色模式要单独适配:
@media (prefers-color-scheme: dark) { mark { background-color: #ffca28; color: #121212; } } - 禁用
background: none—— 它不清除background-image,应写background-color: transparent
动态插入 <mark> 时,innerHTML.replace() 是高危操作
用户搜 [a-z],正则没转义 → new RegExp(keyword) 报错中断;搜 <script>alert(1)</script> → 拼进字符串后执行脚本;原文含 <code>console.log()</code> → 替换后变成 <code>console.<mark>log</mark>()</code>,DOM 解析失败。
- 正确路径:用
document.createTreeWalker(element, NodeFilter.SHOW_TEXT)遍历纯文本节点 - 跳过空节点:
node.textContent.trim() === '' - 关键词必须双重转义:
— HTML 转义:keyword.replace(/[&"'`=/]/g, c => `${c.charCodeAt(0)};`)
— 正则转义:keyword.replace(/[.*+?^${}()|[]]/g, '\$&') - 匹配后创建元素:
const mark = document.createElement('mark'); mark.textContent = match;,再用node.parentNode.replaceChild(mark, node)
中文分词、重叠匹配与嵌套陷阱
用户搜“脚本”和“JavaScript”,若先匹配短词,“JavaScript”里的“脚本”会被提前切开,导致闭合错乱;<mark>React<mark>Native</mark></mark> 是非法 HTML,浏览器强制拆成两个独立 <mark>,样式无法连贯。
立即学习“前端免费学习笔记(深入)”;
- 多关键词高亮必须按长度降序排序,先匹配长词(如 “JavaScript”),再短词(如 “脚本”)
- 禁止嵌套 ——
<mark>只能包裹纯文本,不能包含其他标签或另一个<mark> - 富文本内(如含
<strong>、<em>的段落)必须逐个文本节点处理,不能跨节点匹配 - 大小写敏感需加
gi标志,但替换时要用捕获组保留原大小写:node.textContent.replace(new RegExp(`(${escaped})`, 'gi'), (_, p1) => { const mark = document.createElement('mark'); mark.textContent = p1; return mark; })
<mark> 是否还在语义轨道上?



















