如何对图片缺失 alt 属性自动补空并告警

解读

面试官想考察两点:

  1. 你是否熟悉 Grunt 插件生态任务编排思路
  2. 你是否具备 可落地的工程化方案——既要“补空”保证页面可访问性合规,又要“告警”让开发者第一时间感知问题,避免静默修复带来的技术债。
    国内大厂(阿里、腾讯、字节)在 2023 年后把 无障碍合规 纳入 CI 门禁,图片 alt 缺失直接阻断合并,因此答案必须体现 “本地开发阶段提前拦截 + 持续集成阶段二次校验” 的双保险策略。

知识点

  • grunt-htmlhint:国内团队使用频率最高的静态模板检查器,支持自定义 rule,可二次开发 alt 缺失规则。
  • grunt-contrib-htmlmin:在压缩阶段自动补全 alt="",保证输出产物无语法错误。
  • grunt-log-alt-missing:自研微插件,利用 Cheerio 解析 DOM,把缺失文件名、行号、列号输出成 JUnit XML,供 Jenkins / GitLab CI 解析为红线报告。
  • Grunt 多任务并发:通过 grunt-concurrent 把“补空”与“告警”拆成两条并行流水线,降低本地 dev 反馈时长。
  • 国内合规要求:参照 工信部《无障碍网站设计规范》WCAG 2.1 级别 A,alt 为强制属性,缺失即视为缺陷。

答案

  1. 安装依赖
    npm i -D grunt-htmlhint grunt-contrib-htmlmin grunt-log-alt-missing grunt-concurrent

  2. 在项目根新建 grunt/tasks/alt_missing.js 自定义规则
    module.exports = function(grunt) { grunt.registerMultiTask('altMissing', function() { const fs = require('fs'); const cheerio = require('cheerio'); const junit = []; this.filesSrc.forEach(file => { const =cheerio.load(fs.readFileSync(file,utf8));= cheerio.load(fs.readFileSync(file, 'utf8')); ('img:not([alt])').each((i, el) => { const line = el.startIndex ? el.startIndex.split(':')[0] : 0; junit.push({ name: file, failure: 第${line}行 img 缺失 alt 属性 }); // 补空 (el).attr('alt', ''); }); fs.writeFileSync(file, .html()); }); // 输出 JUnit 格式供 CI 解析 const xml = require('junit-report-builder') .testSuite().name('alt-missing') .testCase().className('Accessibility').name('alt'); junit.forEach(j => xml.failure(j.failure)); xml.writeTo('reports/alt-missing.xml'); if (junit.length) { grunt.log.warn(发现 ${junit.length} 处 img 缺失 alt,已补空并生成报告); } }); };

  3. Gruntfile.js 配置
    module.exports = function(grunt) { grunt.initConfig({ htmlhint: { options: { htmlhintrc: '.htmlhintrc' // 内含 alt-require: true }, src: ['src//*.html'] }, altMissing: { src: ['src//.html'] }, htmlmin: { options: { removeRedundantAttributes: false }, // 保留我们补的 alt="" dist: { expand: true, cwd: 'src', src: '**/.html', dest: 'dist' } }, concurrent: { dev: ['htmlhint', 'altMissing'] } });

    grunt.registerTask('default', ['concurrent:dev', 'htmlmin']); };

  4. 本地运行
    npx grunt
    控制台立即出现 黄色警告 并定位到文件行号;同时生成 reports/alt-missing.xml,Jenkins 解析后若存在 failure 则合并请求标红。

  5. CI 阶段
    .gitlab-ci.yml 增加
    test:accessibility: script: npx grunt altMissing artifacts: reports: junit: reports/alt-missing.xml
    实现 MR 红线 机制,确保任何新增 img 都必须显式写 alt,否则无法进入主干。

拓展思考

  • 性能优化:当项目模板量 > 2000 文件时,可改用 grunt-newer 只扫描 git diff 出的变更文件,把本地检查耗时从 30s 降到 3s。
  • 国际化场景:若站点需要 中英文切换,可在 altMissing 任务里读取 i18n JSON,把空 alt 自动填充为对应语言占位符,如 alt="{{$t('product.imgAlt')}}",让翻译同学后续统一补文案。
  • 与 Vite/Webpack 并存:老项目仍用 Grunt,新模块用 Vite,可通过 grunt-shell 调用 eslint-plugin-jsx-a11y 对 JSX 中的 <img> 做同样检查,实现 “双构建引擎、同一套无障碍门禁”,避免规范断层。