比利时网络无障碍指南在非文本内容方面的条款,本质上是对WCAG 2.1成功标准1.1.1的本地化补充。它的核心诉求并不是要求所有图像都必须携带alt文本,而是要求每个非文本内容在语义上能够被辅助技术等价呈现。封装IWAC的TypeScript模块时,最容易忽略的一点是,指南中的例外条件——比如装饰性图像、验证码、测试题中的图像——不能被简单归为通过或失败。我们需要先把非文本内容类型化,再让校验规则消费这些类型。

一、从指南条款中拆解非文本内容的判别维度
非文本内容的范围远不止<img>元素。图标、图形符号、表单中的图像按钮、<svg>、<canvas>、<object>以及仅提供音频或视频时间轴的内容都属于需要判别的对象。比利时指南对每一类内容的替代文本要求并不相同:装饰性元素应当从可访问性树中移除,验证码可以不提供描述,而功能性图像则必须给出明确的操作名称。如果把这些维度全部塞进一个布尔函数里,后续维护会非常痛苦。
为了在TypeScript中建立稳定的抽象,可以先定义一个节点类型,把DOM查询结果归一化。下面的代码将元素类别、文本替代字段、装饰性标志和用户输入属性分别用独立字段表示,避免规则函数再去反复读取DOM。
type NonTextKind = 'img' | 'svg' | 'canvas' | 'audio' | 'video' | 'object';
interface NonTextNode {
kind: NonTextKind;
selector: string;
role?: string;
alt?: string;
ariaLabel?: string;
ariaLabelledby?: string;
title?: string;
href?: string;
isDecorative: boolean;
isUserInput: boolean;
isTimeBasedMedia: boolean;
}这一层封装后,IWAC规则只与NonTextNode交互,不直接依赖浏览器API。这样做既方便在Node.js环境中跑批量审计,也能在浏览器扩展中复用同一套类型定义。
二、使用联合类型表达豁免与失败条件
很多无障碍检查工具只输出一个布尔值,但比利时指南的判定结果至少包含三类状态:通过、失败和豁免。失败情况还需要区分是缺少alt、alt与aria-label重复,还是角色使用错误。用TypeScript的字符串字面量联合类型来建模这些状态,可以避免手写字符串常量的拼写错误。
type AltDecision =
| { status: 'pass' }
| { status: 'fail'; reason: 'missing-alt' | 'redundant-alt' | 'incorrect-role' }
| { status: 'exempt'; reason: 'decorative' | 'captcha' | 'test' | 'sensory' };在这个类型里,status字段是判别联合的公共属性,reason只出现在失败和豁免状态中。TypeScript会根据当前分支自动收窄类型,在写聚合报告时能避免访问不存在的字段。下面是一个规则判定函数,把指南中的常见豁免条件翻译成代码分支。
function evaluateNonText(node: NonTextNode): AltDecision {
if (node.isDecorative) {
return { status: 'exempt', reason: 'decorative' };
}
if (node.isUserInput && node.kind === 'img' && !node.alt && !node.ariaLabel) {
return { status: 'fail', reason: 'missing-alt' };
}
if (node.role === 'img' && node.alt && node.ariaLabel) {
return { status: 'fail', reason: 'redundant-alt' };
}
return { status: 'pass' };
}当规则结果被多个模块消费时,类型守卫非常有用。例如在报告生成器中,只想统计豁免项数量,就可以安全地过滤出豁免结果,而不会误把失败项加进去。
function isExemptDecision(
decision: AltDecision
): decision is Extract<AltDecision, { status: 'exempt' }> {
return decision.status === 'exempt';
}这样处理还有一个性能上的好处:联合类型不会产生额外的运行时对象,所有检查都在编译期完成,不会拖慢大规模页面扫描。
三、封装IWAC规则接口并输出审计报告
IWAC通常以规则集形式接入扫描器,每个规则实现同一个评估接口。使用TypeScript定义这个接口,可以让比利时非文本内容规则与其他IWAC规则保持一致的调用方式,也方便后续做规则编排和结果聚合。
interface IWACRule {
id: string;
evaluate(node: NonTextNode): AltDecision;
}
class BelgianNonTextRule implements IWACRule {
readonly id = 'belgian-non-text-content';
evaluate(node: NonTextNode): AltDecision {
return evaluateNonText(node);
}
}实际审计一个页面时,不会只处理一个节点,而是需要遍历DOM并将每个非文本节点转成NonTextNode,再交给规则评估。下面是一个聚合函数,它接收节点数组并输出结构化报告。
interface AuditReport {
passed: number;
failed: number;
exempt: number;
items: Array<{ selector: string; decision: AltDecision }>;
}
const evaluateAll = (nodes: NonTextNode[]): AuditReport => {
const report: AuditReport = { passed: 0, failed: 0, exempt: 0, items: [] };
for (const node of nodes) {
const decision = evaluateNonText(node);
if (decision.status === 'pass') {
report.passed++;
} else if (decision.status === 'exempt') {
report.exempt++;
} else {
report.failed++;
}
report.items.push({ selector: node.selector, decision });
}
return report;
};这个报告结构还可以进一步用映射类型生成只读视图或局部更新版本。例如需要把最终报告冻结后交给前端展示,可以写type ReadonlyReport = Readonly<AuditReport>;,这样就不必手动维护另一套接口。
四、在真实DOM检测中处理边界情况
规范层面的类型建模完成后,接入真实DOM时还要考虑可访问性树是否真的暴露了该节点。一个元素可能存在于HTML中,但因为aria-hidden="true"或role="presentation"而对辅助技术不可见。此时即使没有alt文本,也不应判定为失败。为了处理这种情况,可以扩展节点接口,并在规则入口处先做一次可访问性过滤。
interface AccessibleNonTextNode extends NonTextNode {
ariaHidden: boolean;
presentationalRole: boolean;
}
function isExposedToAssistiveTech(node: AccessibleNonTextNode): boolean {
return !(node.ariaHidden || node.presentationalRole);
}在批量审计流程中,可以先调用isExposedToAssistiveTech,未暴露的节点直接跳过,不进入evaluateNonText。这样可以显著减少误报,也更贴合比利时指南对可访问性树的实际要求。
整体来看,用TypeScript为IWAC封装比利时网络无障碍指南的非文本内容类型,本质上是把规则从隐式的DOM判断提升为可复用、可组合的类型系统。这种做法不仅能提升开发体验,还能让无障碍审计结果更可靠、更易于与其他工具集成。
TypeScriptIWAC非文本内容类型修改时间:2026-10-01 11:02:09