CSS Highlight API 自定义绘制与无障碍
用 CSS Highlight API 自定义高亮显示搜索结果,同时保留语义文本、键盘操作、对比度和可访问回退。
BotBrowser Team
CSS Highlight API 能在不修改 DOM 的情况下标出搜索匹配和注释,但高亮只是视觉呈现,不等于语义。BotBrowser 可以重放页面自有的高亮 fixture 并检查可见回退;它不能证明辅助技术朗读、用户阅读意图或浏览器完整的绘制实现。安全契约应明确:把文字保留在 DOM 中,注册有界范围,绘制可区分图层,并保留键盘和语义回退。
TL;DR
CSS.highlights.set('search-hit', new Highlight(range))会为Range设置样式,但不会添加文字、标签或无障碍语义。::highlight(search-hit)等自定义高亮伪元素应使用安全对比度,并且不能成为唯一提示。- 把结果计数放在带
aria-live="polite"的 DOM 区域;分别测试键盘焦点、选择、强制颜色、高倍缩放和减少动画。 - 内容变化后重建范围,限制范围数量与长度,并用
CSS.highlights.delete(name)清理旧条目。 - BotBrowser 可以检查页面状态与回退;本文基于来源写作,不声称运行过 BotBrowser。
Contents
把语义保留在 DOM
高亮 API 改变的是现有文本的绘制方式。Range 指向已经存在的节点,因此屏幕阅读器、复制操作、文本搜索和无 CSS 渲染仍需得到相同的源文本。把结果计数放进 aria-live="polite" 区域,为查询输入提供标签,并为注释提供普通列表或段落。不要只用黄色背景或自定义绘制表达警告。
该 API 与 Selection API 分开。用户选择可由 ::selection 显示;命名自定义高亮是应用持有的 Highlight 对象。给每种状态稳定名称,例如 search-hit 或 current-hit,查询为空时移除它。名称只是 CSS 钩子,不是辅助技术会朗读的标签。
如果要了解相关的视觉身份边界,可阅读 CSS 颜色管理与显示无障碍,其中区分浏览器可见的样式结果与能力主张。Keyboard Layout API 的本地化与隐私 则说明视觉标签不应变成对使用者的推断。Web Components 浏览器兼容性复核还提供了把特性检测与用户承诺分开的支持矩阵方法。
注册有界范围
从已渲染文本节点创建范围,不要从不可信 HTML 字符串创建。fixture 可以遍历文本节点,查找大小写折叠后的查询词,再调用 range.setStart() 和 range.setEnd()。同时限制 MAX_HIGHLIGHTS 与 MAX_MATCH_CHARS;当查询命中数千词时,页面仍应保持响应。
const MAX_HIGHLIGHTS = 100;
const MAX_MATCH_CHARS = 120;
CSS.highlights.delete('search-hit');
CSS.highlights.set('search-hit', new Highlight(...ranges));
具体 fixture 取决于文本节点边界;生产代码必须安全处理嵌套节点和空 firstChild。渲染、本地化、筛选或虚拟列表回收后重算。指向已删除内容的范围是过期状态,不应让旧的高亮对象继续存活。
绘制可见且无障碍的图层
使用 ::highlight(search-hit) 伪元素绘制命名图层,并保持声明简洁。CSS Highlight API 的可样式属性比普通元素少,浏览器可能忽略不支持的属性。选择达到产品对比度目标的前景色和背景色,再在周围界面增加非颜色提示,例如轮廓、图标或结果计数。
::highlight(search-hit) {
color: #111827;
background-color: #fde68a;
text-decoration: underline 0.12em solid #92400e;
}
@media (forced-colors: active) {
::highlight(search-hit) {
color: CanvasText;
background-color: Highlight;
text-decoration: underline;
}
}
不要假定所有引擎或嵌入上下文都以相同方式绘制。检测 CSS.highlights、Highlight 和依赖的选择器;任一前提缺失就显示回退类或可信文本标记。浏览器可见的绘制结果不能证明屏幕阅读器会朗读“匹配”,也不能证明高对比模式保留了所选颜色。
处理选择、焦点和回退
搜索应把焦点移到真实结果控件,而不是移到绘制范围。提供有无障碍名称的上一项和下一项按钮,保留输入查询,并在不困住键盘焦点的情况下滚动到选中结果。用户选择文字时,不要用搜索高亮覆盖 ::selection;两层表达不同状态。
不支持高亮时,在可信文本节点周围添加临时 mark 或 CSS 类,并暴露相同计数和导航。新查询前移除旧回退,避免包装层累积。只读注释可用带 aria-describedby 的相邻说明,比依赖打印或强制颜色中消失的色块更稳妥。
在 200% 缩放、文字间距、仅键盘导航、prefers-reduced-motion 和屏幕阅读器下检查。高亮不应遮挡焦点轮廓、裁剪下伸部,或为每个结果制造闪烁动画。查询为空或无匹配时,清除命名高亮,并在 live region 中宣布“0 个结果”。
用决策表分类结果
| 观察阶段 | 它能证明什么 | 安全的下一步 |
|---|---|---|
CSS.highlights 或 Highlight 缺失 | 当前上下文无法启动命名高亮 | 使用语义 mark 或普通文本,保持导航可用 |
| API 存在但查询为空 | 没有可绘制范围 | 删除 search-hit,宣布已清除并保留焦点 |
| 范围已创建且绘制可见 | 页面应用了一层浏览器可见样式 | 验证对比度、焦点、强制颜色和可访问结果文本 |
| 内容或本地化改变 | 现有偏移量可能过期 | 根据当前文本节点重建范围并丢弃旧对象 |
| 命中数超过 100 | fixture 达到有界工作量 | 显示封顶状态并建议缩小查询,不做无界处理 |
| 强制颜色或打印结果不同 | 用户代理或媒介改变了呈现 | 保留 DOM 结果和非颜色提示作为意义来源 |
每行描述可观察页面条件,不是普遍支持承诺。记录浏览器可见状态、查询长度、范围数和回退分支;不要记录完整文档,也不要推断用户阅读行为。
| 检查点 | 记录内容 | 不能据此推断 |
|---|---|---|
| API 检测 | CSS.highlights=true、Highlight=true | 屏幕阅读器会朗读绘制层 |
| 范围生命周期 | rangeCount=3、长度和节点数 | 文本属于某个身份 |
| 回退 | fallback=mark 与原因 | 整个无障碍栈失效 |
| 焦点路径 | focusTarget=result-2 与键盘顺序 | 用户的阅读意图 |
| 清理 | 删除旧高亮 | 远端状态已经删除 |
| 检查 | 最小记录 | 不要推断 |
|---|---|---|
| API 兼容性 | window.CSS、CSS.highlights、window.Highlight | 所有 CSS 属性都受支持 |
| 查询限制 | MAX_HIGHLIGHTS=100、MAX_MATCH_CHARS=120 | 可以安全保存完整文档 |
| 当前范围 | 源节点与 rangeCount | 文本属于某个身份 |
| 焦点 | focusTarget=result-2 | 使用者想阅读该结果 |
| 视觉模式 | 普通、强制颜色或打印 | 实体显示器使用相同颜色 |
| 清理 | 新渲染前删除名称 | 远端状态已经删除 |
BotBrowser 能力与限制
BotBrowser 可以重放已授权的页面 fixture,注册 Highlight 范围、应用 ::highlight() CSS、更新 live count,并在受控浏览器暴露时练习不支持或强制颜色回退。本文依据下方 W3C 与 MDN 来源撰写,未声称运行 BotBrowser。浏览器检查不能证明屏幕阅读器输出、真实显示器的颜色感知或用户对高亮的理解。
{
"api": "CSS.highlights",
"highlightName": "search-hit",
"rangeCount": 3,
"maxHighlights": 100,
"domResultText": "3 matches",
"assistiveTechnologySpeech": "not-asserted"
}
浏览器发布、本地化、虚拟列表实现或对比度令牌变化后重复 fixture。比较第一个可见差异,并将 DOM 回退保留在验收记录中。
Sources
实践结论
用 CSS Highlight API 自定义绘制强调已有语义的文本。限制并重建范围,把结果状态和导航保留在 DOM 中,并提供对比度安全的非颜色回退。BotBrowser 能重放页面自有状态,但本文没有运行 BotBrowser;输出不能证明屏幕阅读器朗读或用户理解。
本文属于指南: Web 平台能力面:一致性复核地图