如何对图片缺失 alt 属性自动补空并告警
解读
面试官想考察两点:
- 你是否熟悉 Grunt 插件生态 与 任务编排思路;
- 你是否具备 可落地的工程化方案——既要“补空”保证页面可访问性合规,又要“告警”让开发者第一时间感知问题,避免静默修复带来的技术债。
国内大厂(阿里、腾讯、字节)在 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 为强制属性,缺失即视为缺陷。
答案
-
安装依赖
npm i -D grunt-htmlhint grunt-contrib-htmlmin grunt-log-alt-missing grunt-concurrent -
在项目根新建 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 ('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,已补空并生成报告); } }); }; -
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']); };
-
本地运行
npx grunt
控制台立即出现 黄色警告 并定位到文件行号;同时生成 reports/alt-missing.xml,Jenkins 解析后若存在 failure 则合并请求标红。 -
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>做同样检查,实现 “双构建引擎、同一套无障碍门禁”,避免规范断层。