焦点指示器设计系统
目的
焦点指示器设计系统提供了一种系统化的方法,用于设计、指定和审计所有交互元素(按钮、链接、表单输入、自定义切换开关和复杂小部件)的键盘焦点指示器。
焦点指示器是键盘导航者、屏幕阅读器用户以及使用替代输入设备的人的主要视觉寻路工具。当设计师因为“看起来丑”而隐藏默认浏览器焦点环,或者用低对比度的替代方案替换它时,就会立即造成灾难性的无障碍障碍。该系统确保焦点指示器具有品牌特色、高对比度、稳健定位,并符合 WCAG 2.1 和 2.2 标准,同时不影响视觉美学。
使用场景
- 设计系统创建: 在品牌 UI 套件中建立基于全局令牌的焦点状态。
- 组件设计规范: 为复杂元素(例如自定义复选框、范围滑块或选项卡组)定义自定义焦点环。
- 无障碍修复审计: 识别并修复现有网站上不可见或低对比度的焦点轮廓。
- 主题和背景适配: 标准化浅色、深色和品牌色背景下的焦点指示器。
- 跨平台输入优化: 配置
:focus-visible行为,确保鼠标用户看不到分散注意力的焦点环,而键盘导航者则能看到高可见性指示器。
何时不使用
- 静态内容: 不要为非交互元素(例如纯段落、图像、标题或没有链接的信息卡片)设计焦点指示器。
- 原生未修改控件: 如果项目完全依赖默认浏览器控件,没有任何自定义样式或品牌覆盖,并且原生焦点行为完全没有被修改。
- 替代寻路模态: 在语音控制的智能显示器或纯触摸的原生移动应用中,键盘式焦点环不是平台标准无障碍架构的一部分。
输入
- 品牌色板和背景令牌: 核心颜色、背景颜色(浅色、深色和品牌色调)以及容器边框。
- 交互元素清单: 需要焦点状态的所有交互 UI 组件列表(按钮、链接、文本字段、单选按钮、自定义覆盖层)。
- 圆角半径系统: 组件圆角的令牌值(例如
--radius-s、--radius-m),以确保焦点环与元素形状匹配。 - 目标 WCAG 级别: 标准 AA 最低合规性(WCAG 2.1/2.2)或 AAA 目标。
输出
- 全局焦点令牌: 标准化设计令牌,定义焦点环颜色、厚度、轮廓样式和偏移间距。
- 组件特定焦点规范: 内部焦点环、外部焦点环和复杂嵌套轮廓的空间布局规则。
- 高对比度(强制颜色)样式规则: 确保与 Windows 强制颜色模式兼容的 CSS 规范。
- 焦点可见性集成逻辑: 将键盘导航提示与鼠标点击响应分开的规范。
工作流程
1. 编录组件上下文
审计交互组件并按容器背景分组,以确定焦点对比度要求:
- 浅色背景: 需要深色焦点环。
- 深色背景: 需要浅色焦点环。
- 品牌背景(例如鲜艳蓝色): 可能需要中性白色或二次高对比度环,因为标准品牌色轮廓会与背景融合。
2. 定义尺寸与放置模型
选择元素与其焦点环之间的几何关系:
- 外部偏移轮廓: 焦点环通过透明间隙定位在元素边框外部。推荐用于按钮、标签和链接。
- 内部焦点环: 焦点环定位在元素边框内部。推荐用于文本字段、选择菜单和因
overflow: hidden而裁剪的项目。 - 对比光环(双环): 一个外部环包裹在对比鲜明的二次线条中(例如 2px 白色环带 1px 黑色轮廓)。极其稳健,因为它保证在任何背景上都能可见。
3. 建立 WCAG 对比度与尺寸令牌
确定满足 WCAG 的最低样式值:
- 设置焦点环厚度最小为 2px(最好 3px)。
- 保持与相邻背景以及元素未聚焦状态的最小对比度为 3:1。
- 确保焦点指示器的表面积至少等于控件周长上 2px 实线边框的面积(WCAG 2.2 焦点外观)。
4. 分离指针与键盘状态
通过使用 :focus-visible 伪类避免“设计摩擦”。
- 键盘导航(
:focus-visible): 触发高对比度、视觉突出的焦点指示器。 - 鼠标/触摸交互(
:focus不带:focus-visible): 对于鼠标点击,保持焦点环被抑制或极其微妙,防止设计投诉,同时保持完全无障碍。
5. 定义高对比度模式回退
确保焦点指示器在辅助样式偏好(如 Windows 高对比度模式/强制颜色)下不会消失:
- 原生
outline带有透明颜色,会被强制颜色自动映射,但自定义box-shadow样式会被丢弃。 - 始终包含一个
outline回退(即使设置为outline: 2px solid transparent或在媒体查询中使用outline-color: CanvasText),以便高对比度模式渲染出可见的轮廓。
决策规则
规则 1:内部与外部环放置
- 如果元素具有自定义边框且没有溢出遮罩(
overflow: hidden),则使用外部偏移轮廓。 - 如果元素是紧凑网格的一部分、其父容器有
overflow: hidden,或者是文本输入字段(外部轮廓会与相邻元素重叠),则使用内部焦点环(box-shadow: inset ...)。
规则 2:单色与双色光环
- 如果背景是统一且可预测的(例如始终为浅色或始终为深色),且对比度经验证 >= 3:1,则使用单色环。
- 如果元素位于图像、渐变、用户生成内容之上,或者在变化的背景之间滑动(例如跨越区域边界的粘性页眉),则使用双色对比光环(例如深蓝色内部,纯白色外部)。
规则 3:焦点环边框圆角
- 焦点轮廓必须镜像其父控件的
border-radius。 - 确保
outline-offset为正(例如2px或4px),并且轮廓的圆角与卡片/按钮的曲率匹配,或者使用box-shadow(它会自然映射到组件的圆角)。
正确:
[ 按钮(半径 8px) ]
(间隙:2px)
============================= 焦点轮廓(半径 10px)
错误:
[ 按钮(半径 8px) ]
(间隙:2px)
----------------------------- 焦点轮廓(尖锐的 90 度角)
约束条件
- 无障碍(对比度): 焦点环与其周围背景的对比度必须至少为 3:1(WCAG 2.1 SC 1.4.11 非文本对比度)。
- 无障碍(可见性): 指示器必须完全可见。焦点指示器绝不能被粘性页眉、浮动聊天小部件或覆盖层遮挡(WCAG 2.2 SC 2.4.11 焦点不被遮挡)。
- 无障碍(外观): 焦点指示器必须足够大。它必须满足 WCAG 2.2 SC 2.4.13(焦点外观)的计算:最小宽度 2px,最小面积等于周长的 2px 乘以。
- 响应式: 焦点指示器不得拉伸容器或触发水平页面布局溢出。始终使用绝对定位、绝对 CSS 轮廓或内部 box-shadow,这些不会改变 DOM 布局流。
常见失败模式
:focus { outline: none; }清除器: 完全隐藏焦点指示器,而不用稳健的伪类替换。- 低对比度“鬼影”环: 在白色背景上使用浅灰色轮廓,使得活跃焦点状态对低对比度视力的用户不可见。
- “剪切轮廓”陷阱: 将外部焦点环放置在嵌套在具有
overflow: hidden的容器内的元素上。焦点指示器在左右两侧被切断,只留下水平条状部分。 - “粘性页眉遮挡”: 通过 Tab 键聚焦到视口顶部的锚元素,但粘性导航栏重叠并完全遮挡了它(WCAG 2.2 SC 2.4.11 违规)。
- 点击触发焦点混乱: 不使用
:focus-visible,导致每次鼠标点击都闪烁厚重的蓝色环,这令设计团队沮丧,并促使他们要求完全移除焦点样式。 - 强制颜色擦除: 仅使用 CSS 自定义属性和
box-shadow值构建漂亮的焦点环,而没有透明的outline回退,导致在 Windows 高对比度模式下焦点指示器完全不可见。
验证标准
- 每个交互元素在使用
Tab键导航时都显示高度可见、清晰的焦点指示器。 - 每个全局和组件焦点指示器的对比度经验证 >= 3:1(与其背景相比)。
- 自定义焦点样式使用
:focus-visible选择器,确保在键盘导航时触发,但在鼠标点击时保持干净。 - 没有焦点指示器被父容器的
overflow: hidden规则剪切或截断(要么调整了偏移,要么切换为内部)。 - 靠近粘性页眉或浮动元素的键盘导航,使焦点元素保持完全可见(使用
scroll-margin-top覆盖)。 - 在高对比度/强制颜色模式下,使用透明轮廓规则验证焦点指示器。
- 自定义指示器的周长表面积满足 WCAG 2.2 SC 2.4.13 的最小计算。