大模型驱动的无障碍设计审查:自动化 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 resultsaxe-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 results3.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 results3.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 审查的不确定性和延迟成本,采用增量审查和结果缓存策略优化管线效率。最终,自动化审查是辅助工具,不能完全替代真实用户的无障碍测试。