高亮需同时满足XSS防护、DOM安全、语义正确、无障碍播报、多模式适配五层约束;漏任一环将导致盲人不可见或邮件中透明失效。

mark 标签本身就能创建高亮,但直接写 <mark>xxx</mark> 只是起点;真实项目里不处理转义、不遍历文本节点、不显式设样式,90% 的高亮会失效或被拦截。
为什么 document.querySelector('mark') 找不到动态插入的高亮
不是 selector 写错了,也不是大小写问题——mark 在 HTML 中不区分大小写,但查找失败通常因为:
- 高亮是用
innerHTML = ...replace(...)拼出来的,结果把原有事件监听器、contenteditable状态、甚至<script>标签都清空重写了 - 插入后 DOM 尚未重排(比如在
requestIdleCallback或微任务中执行),querySelector查的是旧树 - 目标容器在 Shadow DOM 里,而没走
shadowRoot.querySelector('mark') - Safari 对
contenteditable区域有自动剥离行为,刚插进去的<mark>被静默删了
正则替换关键词时必须做的三件事
用户搜 [a-z] 或 React.js,直接传给 new RegExp(keyword) 会报错或匹配错位。安全替换要:
- 先转义正则元字符:
keyword.replace(/[.*+?^${}()|[]\]/g, '\$&') - 加
gi标志保证全局 + 不区分大小写(中文场景可去i) - 用捕获组 + 回调函数保留原文本大小写,别用字符串模板:
str.replace(regex, (match) => { const el = document.createElement('mark'); el.textContent = match; return el.outerHTML; })(注意:outerHTML仍有 XSS 风险,生产环境优先用insertAdjacentElement)
样式必须显式声明,浏览器默认值不可交付
Chrome 默认黄色背景在以下场景会彻底消失:
将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。
立即学习“前端免费学习笔记(深入)”;
- Windows 高对比度模式下强制黑底白字
- Safari 阅读模式忽略所有 UA 样式
- Outlook 等邮件客户端禁用
mark默认背景 - 项目用了
* { background: transparent }这类重置规则
至少写死这四条:background-color、color、padding、border-radius。深色模式建议补媒体查询:@media (prefers-color-scheme: dark) { mark { background-color: #ffeb3b; color: #212121; } }。
真正难的是五层约束同时满足
不是“怎么让字变黄”,而是让高亮在 XSS 防御、DOM 结构安全、语义正确、屏幕阅读器播报、暗色/高对比度适配这五层约束下稳定生效。漏掉任何一层,搜索页对盲人用户就是“不可见”的,或者在邮件里“完全透明”。最常被跳过的其实是中文词界处理和多关键词长度排序——比如同时高亮 JavaScript 和 Script,不按长度降序,Script 就会插进已闭合的 <mark> 里,破坏语义。


















