大模型驱动的无障碍设计审查:自动化 WCAG 合规检测
大模型驱动的无障碍设计审查:自动化 WCAG 合规检测

一、无障碍的"合规盲区":手动审查的覆盖率困境
Web 无障碍(Accessibility)合规是法律要求(欧盟 EN 301 549、美国 ADA),但大多数团队的无障碍审查依赖手动检查。一个中等复杂度的页面包含 50+ 个交互元素,每个元素需要检查颜色对比度、焦点顺序、ARIA 标签、键盘可达性等 10+ 项规则。全量手动审查一个页面需要 2-3 小时,而产品迭代周期可能只有 1 周。结果是:无障碍审查被压缩到"上线前扫一眼",大量合规问题被遗漏。自动化工具(axe-core、Lighthouse)能检测 30%-40% 的规则,但语义层面的审查(如 ARIA 标签是否准确描述了元素功能)仍需人工判断。
二、WCAG 规则体系与自动化检测边界
2.1 WCAG 规则的分类与自动化可行性
flowchart TB
A[WCAG 2.2 规则] --> B[可自动化检测<br/>约 40%]
A --> C[需语义理解检测<br/>约 35%]
A --> D[需上下文判断<br/>约 25%]
B --> B1[颜色对比度]
B --> B2[HTML 语义结构]
B --> B3[焦点顺序]
B --> B4[表单标签关联]
C --> C1[ARIA 标签准确性]
C --> C2[图片替代文本质量]
C --> C3[链接文本描述性]
C --> C4[标题层级合理性]
D --> D1[错误提示可理解性]
D --> D2[多模态内容等效性]
D --> D3[动画可暂停性]
D --> D4[认知负荷评估]
2.2 传统自动化工具的局限
from playwright.sync_api import sync_playwright
def run_axe_audit(url: str) -> dict:
"""使用 axe-core 进行自动化无障碍审查"""
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto(url)
# 注入 axe-core 并执行审查
results = page.evaluate("""
async () => {
const results = await axe.run();
return {
violations: results.violations.map(v => ({
id: v.id,
impact: v.impact,
description: v.description,
nodes: v.nodes.map(n => ({
html: n.html,
target: n.target,
})),
})),
};
}
""")
browser.close()
return results
axe-core 能检测对比度不足、缺少 alt 属性、焦点顺序错误等结构性问题,但无法判断:alt 文本是否准确描述了图片内容、ARIA 标签是否与元素功能匹配、错误提示是否对用户友好。
三、大模型驱动的语义审查方案
3.1 基于 LLM 的 ARIA 标签质量评估
import json
class AriaLabelAuditor:
"""使用 LLM 评估 ARIA 标签的准确性和描述性"""
def __init__(self, llm_client):
self.llm = llm_client
def audit_aria_labels(self, elements: list) -> list:
"""批量审查 ARIA 标签质量"""
results = []
for elem in elements:
prompt = f"""评估以下 HTML 元素的 ARIA 标签质量。
元素类型: {elem['tag']}
元素功能: {elem.get('role', '未指定')}
当前 aria-label: {elem.get('aria_label', '未设置')}
元素上下文: {elem.get('context', '无')}
视觉外观描述: {elem.get('visual_desc', '无')}
请从以下维度评估:
1. 准确性:标签是否准确描述了元素功能
2. 简洁性:标签是否简洁(建议15字以内)
3. 唯一性:标签是否与页面上其他元素区分
4. 一致性:标签风格是否与页面其他标签一致
输出 JSON 格式:
{{"score": 0-10, "issues": [...], "suggestion": "..."}}"""
response = self.llm.chat(prompt)
assessment = json.loads(response)
assessment['element'] = elem
results.append(assessment)
return results
3.2 图片替代文本质量评估
class AltTextAuditor:
"""评估图片替代文本的质量"""
def __init__(self, llm_client, vision_client):
self.llm = llm_client
self.vision = vision_client
def audit_alt_text(self, images: list) -> list:
"""对比图片实际内容与 alt 文本的匹配度"""
results = []
for img in images:
# 1. 使用视觉模型理解图片内容
actual_content = self.vision.describe(img['src'])
# 2. 评估 alt 文本与实际内容的匹配度
prompt = f"""评估图片替代文本的质量。
图片实际内容: {actual_content}
当前 alt 文本: {img.get('alt', '未设置')}
评估维度:
1. 信息完整性:alt 是否传达了图片的关键信息
2. 简洁性:alt 是否避免冗余描述(如"图片显示...")
3. 功能性:对于装饰性图片,alt 是否为空
4. 上下文相关性:alt 是否匹配图片在页面中的用途
输出 JSON: {{"score": 0-10, "issues": [...], "suggestion": "..."}}"""
response = self.llm.chat(prompt)
assessment = json.loads(response)
assessment['image_src'] = img['src']
results.append(assessment)
return results
3.3 综合审查管线
class AccessibilityAuditPipeline:
"""自动化 + LLM 的综合无障碍审查管线"""
def __init__(self, llm_client, vision_client):
self.aria_auditor = AriaLabelAuditor(llm_client)
self.alt_auditor = AltTextAuditor(llm_client, vision_client)
def audit_page(self, url: str) -> dict:
"""执行完整的页面无障碍审查"""
# 阶段1:结构化自动化检测(快速、确定性)
auto_results = run_axe_audit(url)
# 阶段2:提取需要语义审查的元素
elements = self._extract_semantic_elements(url)
# 阶段3:LLM 语义审查(慢速、概率性)
aria_results = self.aria_auditor.audit_aria_labels(
elements['interactive']
)
alt_results = self.alt_auditor.audit_alt_text(
elements['images']
)
# 阶段4:合并结果并生成报告
report = {
'url': url,
'auto_violations': len(auto_results['violations']),
'semantic_issues': len(aria_results) + len(alt_results),
'total_score': self._compute_score(
auto_results, aria_results, alt_results
),
'details': {
'auto': auto_results,
'aria': aria_results,
'alt_text': alt_results,
},
}
return report
def _extract_semantic_elements(self, url: str) -> dict:
"""从页面提取需要语义审查的元素"""
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto(url)
elements = page.evaluate("""
() => {
const interactive = Array.from(
document.querySelectorAll(
'[aria-label], [aria-labelledby], button, a, input'
)
).map(el => ({
tag: el.tagName,
role: el.getAttribute('role'),
aria_label: el.getAttribute('aria-label'),
context: el.parentElement?.tagName,
visual_desc: el.textContent?.slice(0, 100),
}));
const images = Array.from(
document.querySelectorAll('img')
).map(el => ({
src: el.src,
alt: el.alt,
role: el.getAttribute('role'),
}));
return { interactive, images };
}
""")
browser.close()
return elements
四、边界分析与架构权衡
4.1 LLM 审查的不确定性
同一元素在不同 LLM 调用中可能给出不同评分,评分标准受模型版本和提示词措辞影响。缓解策略:对关键规则使用确定性规则引擎(axe-core),LLM 仅补充语义层面审查;对 LLM 结果取多次采样的众数。
4.2 审查延迟与成本
一个包含 50 个交互元素和 20 张图片的页面,LLM 语义审查需要 70 次 API 调用,耗时约 2-3 分钟,成本约 0.5-1 美元。在 CI/CD 管线中,这可能导致构建时间显著增加。优化方案:增量审查(只检查变更元素)、缓存已审查结果。
4.3 视觉模型的描述偏差
视觉模型对图片的理解可能存在偏差——将装饰性图标描述为"信息图表",导致 alt 文本建议过于详细。需要结合 HTML 上下文(元素尺寸、位置、role 属性)综合判断图片的功能性角色。
4.4 合规性 vs 用户体验
WCAG 合规是底线,但合规不等于好的无障碍体验。一个技术上合规的 ARIA 标签可能对屏幕阅读器用户毫无帮助(如 aria-label="按钮")。LLM 审查应同时评估"合规性"和"实用性",后者需要更多用户测试数据支撑。
五、总结
大模型驱动的无障碍设计审查,填补了传统自动化工具在语义层面的检测空白。axe-core 负责结构化规则检测(对比度、焦点顺序、HTML 语义),LLM 负责 ARIA 标签准确性、alt 文本质量和错误提示可理解性等语义审查。两者结合可将无障碍检测覆盖率从 40% 提升到 75%+。工程实践中需注意 LLM 审查的不确定性和延迟成本,采用增量审查和结果缓存策略优化管线效率。最终,自动化审查是辅助工具,不能完全替代真实用户的无障碍测试。
更多推荐


所有评论(0)