为什么使用WebP格式后图片在移动端显示模糊,该怎么解决?
我在项目里用WebP格式压缩图片,发现手机端显示的图片边缘特别模糊,这是为什么?
之前用这个JS脚本自动替换图片格式:
document.querySelectorAll('img').forEach(img => {
const src = img.src.replace(/.(jpe?g|png)$/, '.webp');
img.src = src;
});
测试时发现iPad Pro的图片文字边缘锯齿严重,而电脑上看没问题。尝试过加了但没效果,是不是需要调整压缩参数?或者WebP在移动端有特殊设置?
先说原因。WebP是有损压缩,如果你用默认的质量参数(有些工具默认只有75甚至更低),边缘细节会被吃掉。iPad Pro这种高分屏对细节敏感,一放大就露馅,电脑屏幕DPI低反而看不出来。
你那个JS替换方案也很粗暴,直接换个后缀就完事了,服务端生成WebP的时候质量参数控制了吗?
几个解决方案:
第一,转换WebP时把质量参数调高。用sharp或者imagemin的话,quality至少设85以上,边缘敏感的图直接拉到90。我用sharp的配置:
alphaQuality是透明通道质量,PNG转WebP的时候这个很关键,设低了边缘会有毛边。
第二,高DPI设备要提供2x甚至3x的图。你只替换格式不换尺寸,高分屏上图片被浏览器放大渲染,当然糊。用srcset搞定:
这样浏览器自己按设备像素比选合适的图,缓存起来也方便。
第三,如果你不想搞多套图,至少保证原图尺寸是显示尺寸的2倍。比如页面上显示100x100的图,源文件至少200x200。
另外你那个JS方案效率很低,DOMContentLoaded之后还要遍历所有DOM元素做替换,每个图片还要再发一次请求。要么服务端直接输出WebP,要么用nginx或者CDN做自动转换,别在前端搞这种hack。
检查一下你的WebP生成参数,90%的情况下调高质量参数就能解决。
建议把图片转换逻辑移到后端处理,这样可以精细控制压缩参数。比如用Node.js可以这样写:
重点是quality参数,移动端建议设为85以上,lossless设为false即可,不要盲目追求压缩率。如果图片中有文字或图标,WebP的有损压缩会对边缘做平滑处理,造成锯齿感。这时候可以考虑用PNG格式或者开启sharp的
effort参数提升压缩质量。另外iOS系统对WebP兼容性比安卓差,有些老版本系统根本不支持。建议后端加个UA判断,对iOS设备返回PNG格式,或者前端JS检测User-Agent再决定是否替换为WebP: