@a11y-oracle/焦点分析器
无障碍测试的重点状态分析. 提供视觉焦点指标检查,WCAG对比比计算,DOM制取分页指令,以及键盘陷阱检测.
这是内部使用的低层构件 @a11y-oracle/core-engine。大多数用户应该使用 Playwright 或 Cypress 插件.
安装
npm install @a11y-oracle/focus-analyzer
使用量
import { FocusAnalyzer } from '@a11y-oracle/focus-analyzer';
const analyzer = new FocusAnalyzer(cdpSession);
// Analyze the focus indicator on the currently focused element
const indicator = await analyzer.getFocusIndicator();
console.log(indicator.isVisible); // true
console.log(indicator.contrastRatio); // 12.63
console.log(indicator.meetsWCAG_AA); // true (visible + contrast >= 3.0)
console.log(indicator.outlineColor); // "rgb(0, 95, 204)"
console.log(indicator.outlineWidth); // "3px"
// Extract all tabbable elements in DOM tab order
const entries = await analyzer.getTabOrder();
entries.forEach(e => {
console.log(`${e.index}: ${e.tag}#${e.id} (tabIndex=${e.tabIndex})`);
});
// Detect keyboard traps (WCAG 2.1.2)
const result = await analyzer.detectKeyboardTrap('#modal-container', 20);
if (result.isTrapped) {
console.log('Focus is trapped!');
} else {
console.log(`Focus escaped to: ${result.escapeElement?.tag}`);
}
API 参考
FocusAnalyzer
constructor(cdp: CDPSessionLike)
创建一个新的焦点分析器 。 内部创建 a KeyboardEngine 用于探测陷阱.
cdp- 任何 CDP 兼容的会话(使用CDPSessionLike界面从@a11y-oracle/cdp-types) (中文(简体) ).
getFocusIndicator(): Promise<FocusIndicator>
分析当前焦点元素的视觉焦点指标.
提取计算 CSS 属性(outline, (中文(简体) ), box-shadow, (中文(简体) ), border-color, (中文(简体) ), background-color)通过 Runtime.evaluate,然后对照背景计算焦点指标的对比率.
如果没有元素焦点,则返回默认的“不可见”指标.
可见度检测 :
- 元素有可见 大纲 若为
outline-width没有0px和轮廓颜色有一个非零的α通道(探测两个transparent关键词和rgba(0, 0, 0, 0)其 Chrome 报告为透明大纲) - 元素有可见 框阴影 若为
box-shadow没有none
对比计算 :
- 大纲:对比比
outline-color财务报告和审定财务报表background-color - 对于框阴影:取出所有颜色
box-shadow值,过滤出透明值,并使用 最外向可见的颜色 (最后不透明)用于对比计算。 这样可以正确处理Tailwind CSS多环模式,其中装饰的空间器环会先出现而实际的焦点指示环会后出现. - 回返
contrastRatio: null如果颜色不能可靠地解析(例如梯度、复杂的颜色函数)
2.4.12 AA 遵守情况: meetsWCAG_AA 实值 true 当指标可见,而对比比为 QQ 3.0.
getTabOrder(): Promise<TabOrderEntry[]>
按标签顺序从 DOM 中提取所有可制表元素 .
可聚焦要素的查询(a[href], (中文(简体) ), button:not([disabled]), (中文(简体) ), input:not([disabled]), (中文(简体) ), select:not([disabled]), (中文(简体) ), textarea:not([disabled]), (中文(简体) ), [tabindex],然后过滤出 :
- 要件
tabIndex < 0 - 隐藏元素( E)
display: none, (中文(简体) ),visibility: hidden(中文(简体) ) - 无布局的元素( N)
offsetParent === null(中文(简体) ) - 内部要素
[inert]集装箱
结果按 tabIndex 数值:正数 tabIndex 数值首先(升起),然后 tabIndex=0 dOM 顺序中的元素.
detectKeyboardTrap(selector: string, maxTabs?: number): Promise<TraversalResult>
检测焦点是否被困在容器内(WCAG 2.1.2).
- 将第一个可制表元素放在容器匹配中
selector - 多次按下标签(最多
maxTabs,默认为50) - 每个标签后检查焦点是否离开了容器
- 如果焦点脱逃,立即返回,或者如果
maxTabs已经用尽
回返 { isTrapped: false, tabCount: 0 } 如果容器不存在或没有可聚焦元素.
纯公用函数
软件包还输出纯函数用于色彩解析和WCAG对比计算:
parseColor(css: string): RGBColor | null
将 CSS 颜色字符串分析为 RGBColor 对象。 支持 :
rgb(r, g, b)财务报告和审定财务报表rgba(r, g, b, a)- 十六进制颜色 :
#RGB, (中文(简体) ),#RRGGBB, (中文(简体) ),#RRGGBBAA transparent(回报){ r: 0, g: 0, b: 0, a: 0 }(中文(简体) )
回返 null 用于不支持的格式(名称颜色, hsl(), (中文(简体) ), color()(见a/c.5/49/70,附件).
srgbToLinear(channel: number): number
将 sRGB 通道值 (0-255) 转换为线性光.
relativeLuminance(color: RGBColor): number
计算 WCAG 相对亮度 : L = 0.2126*R + 0.7152*G + 0.0722*B
contrastRatio(color1: RGBColor, color2: RGBColor): number
计算两种颜色之间的WCAG对比比。 返回1(相同)至21(白色黑)之间的值.
meetsAA(ratio: number): boolean
请检查archive-date=中的日期值 (帮助) WCAG AA对焦指标的对比率是否与 WCAG AA相符合(QQ 3.0).
类型
RGBColor
interface RGBColor {
r: number; // 0-255
g: number; // 0-255
b: number; // 0-255
a: number; // 0-1
}
FocusIndicator
全面重点指标分析:
interface FocusIndicator {
isVisible: boolean;
outline: string; // Raw outline shorthand
outlineColor: string; // e.g. "rgb(0, 95, 204)"
outlineWidth: string; // e.g. "3px"
outlineOffset: string; // e.g. "0px"
boxShadow: string; // e.g. "0px 0px 0px 3px rgb(52, 152, 219)"
borderColor: string;
backgroundColor: string;
contrastRatio: number | null;
meetsWCAG_AA: boolean;
}
TabOrderEntry
interface TabOrderEntry {
index: number; // Position in tab order (0-based)
tag: string; // "BUTTON"
id: string;
textContent: string;
tabIndex: number;
role: string;
rect: { x: number; y: number; width: number; height: number };
}
TabOrderReport
interface TabOrderReport {
entries: TabOrderEntry[];
totalCount: number;
}
TraversalResult
interface TraversalResult {
isTrapped: boolean; // true if focus never escaped
tabCount: number; // Total Tab presses attempted
visitedElements: TabOrderEntry[]; // Elements that received focus
escapeElement: TabOrderEntry | null; // First element outside container
}
出口
export { FocusAnalyzer } from '@a11y-oracle/focus-analyzer';
export { parseColor } from '@a11y-oracle/focus-analyzer';
export { srgbToLinear, relativeLuminance, contrastRatio, meetsAA } from '@a11y-oracle/focus-analyzer';
export type { RGBColor, FocusIndicator, TabOrderEntry, TraversalResult, TabOrderReport } from '@a11y-oracle/focus-analyzer';
限制
- 复杂的重点指标 - 梯级,CSS
color-mix(),其它高级色彩函数返回contrastRatio: null因为它们无法可靠地解析成单一的颜色值. - 键盘陷阱检测 ——仅用 Tab 键进行测试. 故意聚焦陷阱(如模式对话框)应当与"逃生"键导航单独测试.
tabIndex命令 ——制表命令提取遵循了标准算法(正数)tabIndex先说tabIndex=0在DOM顺序中),但不计入Shadow DOM边界.