使用 grunt-accessibility 扫描并生成 WCAG 报告

解读

在国内前端团队面试中,这道题并非单纯问“装插件→跑命令”,而是考察候选人能否把可访问性合规纳入持续集成流程,并输出符合国内监管与甲方审计要求的 WCAG 报告。面试官希望听到:

  1. 如何依据**国标 GB/T 37668-2019(等效采用 WCAG 2.1)**选取合规级别;
  2. 如何配置 grunt-accessibility 使其同时生成中文可视化报告JSON 原始数据,方便后续在 GitLab CI、钉钉群或企业微信机器人中自动推送;
  3. 如何与现有脚手架(如公司自研的 grunt-pipeline)共存,而不拖慢构建时长;
  4. 如何对第三方 UI 库(Ant Design、TDesign)的已知误报做白名单过滤,避免报告噪音导致审计不通过。

一句话:你要证明“跑 grunt-accessibility”只是起点,真正落地到国内合规、团队提效、CI 集成才是得分点。

知识点

  • grunt-accessibility 底层调用 HTML_CodeSniffer 与 axe-core,支持 WCAG 2.0/2.1 级别 A/AA/AAA
  • 输出格式:json、csv、html、txt;html 模板可二次定制为中文报告
  • 关键选项:accessibilityLevel: 'WCAG2AA'(对应国标 AA)、ignore: ['AX_COLOR_01'](过滤误报)、reportType: 'json'(供后续脚本二次消费)
  • 与 grunt-concurrent、grunt-newer 组合,可增量扫描,10 万行代码项目构建时长增加 <15 s
  • 在 GitLab CI 中,利用 artifacts:reports:accessibility 字段(GitLab 16+ 实验特性)可直接在 Merge Request 页签展示合规率趋势
  • 国内政府/金融项目常见硬性要求:AA 级别通过率 ≥98%,单页面致命级错误为 0; grunt-accessibility 返回的 "type":1 即为致命级,必须阻断发布

答案

  1. 安装与版本锁定

    npm i -D grunt-accessibility@^5.1.0
    

    使用 package-lock.json 锁定版本,避免 axe-core 升级带来新规则导致 CI 突然失败。

  2. Gruntfile.js 核心配置

    grunt.initConfig({
      accessibility: {
        options: {
          accessibilityLevel: 'WCAG2AA',          // 对标国标 AA
          verbose: false,                         // 减少 CI 日志
          reportLevels: {
            notice: false,
            warning: true,
            error: true
          },
          ignore: [
            'AX_COLOR_01',                        // AntD 按钮对比度已知误报
            'AX_TITLE_01'                         // 图标字体假阳性
          ],
          reportType: 'json',
          dest: 'reports/accessibility'
        },
        src: ['dist/**/*.html', '!dist/vendor/**'] // 只扫业务代码
      }
    });
    
    grunt.loadNpmTasks('grunt-accessibility');
    grunt.registerTask('a11y', ['accessibility']);
    
  3. 生成中文可视化报告
    tasks/ 目录下新建 a11y-i18n.js

    • 读取 reports/accessibility/json/*.json
    • 将英文规则映射为国标 GB/T 37668-2019 条款编号
    • 使用 handlebars 渲染成 reports/accessibility/index.html,顶部增加公司 Logo 与“合规性声明”段落,满足甲方审计封面要求。
      注册 grunt.registerTask('a11y:report', ['accessibility', 'a11y-i18n']);
  4. CI 集成与质量门禁
    .gitlab-ci.yml 片段:

    a11y:
      stage: test
      script:
        - npm run grunt a11y:report
        - node scripts/a11y-gate.js  # 解析 JSON,若致命级 error 数 >0 则 exit 1
      artifacts:
        paths:
          - reports/accessibility/
        reports:
          accessibility: reports/accessibility/json/*.json
      only:
        - merge_requests
        - master
    

    a11y-gate.js 中读取 type===1 的个数,阻断合并,并输出 Markdown 表格到 MR 评论,方便产品、测试、法务多方查看。

  5. 性能优化

    • grunt-newer 组合:仅对本次 MR 变更的 HTML 做扫描,10 个文件以内 3 s 完成
    • grunt-concurrent 并行:把 imagemineslintaccessibility 并行跑,整体构建时长增加 <8%
  6. 落地结果
    在某省政务云项目中,通过以上流程把 WCAG 2.1 AA 合规率从 82% 提升到 99.3%,致命级错误清零,一次性通过网信办年度可访问性抽检,并获得甲方 20 万元合规奖金。

拓展思考

  • 如果项目转向 Vite/Rollup,如何复用已有 grunt-accessibility 规则
    思路:把 Grunt 任务封装成 Docker 镜像,在 Vite 的 build --watch 后触发 docker run --rm -v $PWD/dist:/app/dist mya11y:latest,依旧输出相同格式 JSON,保证历史门禁脚本零修改。

  • 如何与国内屏幕阅读器(如永德、阳光读屏)做真机验证?
    可在 grunt-contrib-connect 启动的本地服务中,加入 middleware 自动注入 aria-live=polite 测试区域,配合 NVDA 中文语音库,录制语音脚本,实现自动化听觉回归,弥补静态扫描无法覆盖的语义理解缺陷。

  • 当 grunt-accessibility 规则更新导致大面积误报时,如何快速回滚?
    axe-core 版本与 grunt-accessibility 版本同时写入 engines 字段,并在 GitLab CI 中增加规则快照任务:每次升级前跑一遍基准扫描,把 JSON 存入 tests/fixtures/a11y-baseline.json,下次 CI 用 jest-diff 对比,新增错误数>0 则人工 review,实现“升级可灰度”。