如何对 retina 图片进行 @2x 后缀识别并差异化压缩质量
解读
国内前端项目普遍要兼容高分屏,UI 会输出两套切图:logo.png 与 logo@2x.png。构建阶段必须:
- 识别文件名中的 @2x 标记
- 对 二倍图采用更低压缩比(保留更多细节),普通图采用高压缩比(减少体积)
- 保证目录结构、引用路径不变,避免人工干预
面试官想看你是否能把“文件匹配规则”“条件化任务配置”“Grunt 多任务实例”三个点串起来,而不是只会跑 grunt-contrib-imagemin 默认配置。
知识点
- Gruntfile 多任务目标(targets)机制:同一任务可定义多个 target,各自独立配置
- glob 通配符与扩展名匹配:
**/*@2x.{png,jpg,jpeg}精准命中 retina 图 - imagemin 插件的 optimizationLevel / quality 参数:png 用 optimizationLevel(0-7),jpg 用 quality(0-100)
- grunt-newer 或 grunt-contrib-watch 缓存:避免重复压缩已优化图片,提升 CI 速度
- 文件对象格式(files object):
{src: [], dest: ''}写法可保持目录层级 - 中文跨平台路径问题:Windows 不区分大小写,macOS/Linux 区分,需统一小写后缀
- 国内镜像加速:
npm config set sharp_binary_host=https://npmmirror.com/mirrors/sharp可解决 imagemin 依赖下载慢的问题
答案
- 安装依赖(npm 源已切到国内镜像)
npm i -D grunt grunt-contrib-imagemin grunt-newer
- Gruntfile.js 关键片段
module.exports = function(grunt) {
grunt.initConfig({
imagemin: {
// 普通图高压缩
normal: {
options: {
optimizationLevel: 3, // png
progressive: true, // jpg
quality: 70 // jpg 质量 70
},
files: [{
expand: true,
cwd: 'src/img',
src: ['**/*.{png,jpg,jpeg}', '!**/*@2x.{png,jpg,jpeg}'], // 排除 @2x
dest: 'dist/img'
}]
},
// retina 图低压缩
retina: {
options: {
optimizationLevel: 5, // 更高保真
progressive: true,
quality: 85 // jpg 质量 85
},
files: [{
expand: true,
cwd: 'src/img',
src: ['**/*@2x.{png,jpg,jpeg}'], // 仅 @2x
dest: 'dist/img'
}]
}
}
});
grunt.loadNpmTasks('grunt-contrib-imagemin');
grunt.registerTask('img', ['newer:imagemin:normal', 'newer:imagemin:retina']);
};
- 运行
grunt img
构建后,dist/img 目录下普通图体积下降 50% 以上,@2x 图保留高分屏细节,文件名与路径完全一致,可直接上线。
拓展思考
- 若 UI 输出 3x 图(@3x),可再增加 imagemin.target3x,用 quality 90 + optimizationLevel 6 保证印刷级清晰
- 对 WebP 输出,可再配
grunt-contrib-webp,同样按 @2x 后缀做 quality 75 vs 85 差异化 - 在 CI 中,把
grunt img放到pre-commit钩子,结合 husky + lint-staged,防止大图片误提交 - 若项目用小程序,可将 @2x 图统一打到
assets/_retina目录,利用 grunt-copy 在上传前再合并,减少仓库体积 - 国内 CDN 常自动回源 WebP,可让运维配置 User-Agent 嗅探,此时本地只需保留压缩后的 @2x PNG 作为兜底,无需输出双格式,降低构建时间