ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

移动端图片模糊?从DPR到压缩格式的完整适配指南

移动端图片模糊?从DPR到压缩格式的完整适配指南 先讲个我真实踩过的坑。前两年做移动端改版设计师交付了一套 banner 图Mac 上打开放大 200% 边缘照样锐利。我没多想就把原图丢进了前端页面。结果真机测试的时候用户反馈“首页的图怎么是糊的”尤其是标题文字的边缘像隔了一层磨砂玻璃。当时我先怀疑 CDN 转码又怀疑是手机型号太老排查到最后发现原因特别基础——图片物理分辨率不够手机屏幕的 DPR 去填充。那次之后我把 DPR、压缩、格式选择这三件事彻底捋了一遍今天这篇就是当时的全部心得。这篇文章适合所有被“图片模糊”困扰的人设计师要理解为什么自己导出的资源会在手机上“变样”前端要知道怎么适配不同屏幕密度做性能优化的人也需要弄明白压缩和质量之间的平衡点到底在哪。放心不涉及晦涩算法我会把原理掰开揉碎再给你一套可以直接抄作业的流程。1. 模糊的第一层原因设计稿坐标系和手机坐标系是两套逻辑1.1 设计稿里的“清晰”只存在于设计软件里你在 Sketch、Figma 或 PS 里打开一张图片100% 缩放显示时它之所以清晰是因为此时画布上的 1 个像素恰好对应当前电脑屏幕上的 1 个物理像素如果你的电脑屏幕 DPR1。换句话说设计稿的“清晰”是一种 1:1 的静态预览假象。它没有经过网络传输、没有经过压缩算法、不需要响应不同屏幕的像素密度它只是“这张图在自己的原始分辨率下被完整展示”而已。但一旦图片进入网页或 App情况就变了。前端的世界以 CSS 像素也叫逻辑像素为基准进行布局而手机的屏幕是由物理像素组成的。在绝大多数非入门级手机上一个逻辑像素背后是 2 个或 3 个物理像素。这就意味着一张 100px 宽的图片在普通屏DPR1上需要 100 个物理像素来显示在 Retina 屏上却需要 200 个甚至 300 个物理像素来填充。如果你的源图只有 100 个像素点多出来的 100 或 200 个点从哪来只能靠浏览器用插值算法硬算出来。算出来的点没有真实图像信息人眼感知到的就是边缘发虚、细节丢失——也就是我们常说的“糊”。这里有个很贴切的生活类比你把一张 100×100 的照片贴在墙上然后拿一个 200×200 的相框去展示它中间多出来的区域只能靠后期“脑补”填充脑补出来的画面自然不可能有真实的纹理和边缘信息。手机屏幕干的其实就是这件事。1.2 Retina 屏给设计师制造的“错觉”还有一层隐藏因素现在的设计师多半用 Retina MacBook 工作屏幕本身 DPR2。当你在这种屏幕上以 100% 查看设计稿时系统已经帮你做了一次“缩放渲染”——也就是说你在屏幕上看到的清晰很可能是系统把图放大后做了平滑处理的效果。这种情况下如果你凭视觉判断“这图够清晰”十有八九会误判因为你看的不是原图的实际信息量。所以我在项目里的经验是不要用肉眼在电脑上判断图片清晰度。要判断一张图够不够清晰应该看它的物理分辨率是否达到“显示尺寸 × 目标设备 DPR”这个值。比如一个在手机端占据 320 CSS 像素宽的 banner如果目标机型是 DPR3那么源图宽度至少要为 960 物理像素如果只有 640px在 DPR2 的机型上能看在 DPR3 的机型上就会糊。这是所有后续操作的地基也是很多人最容易忽略的第一步。2. DPR决定“需要多大图”的底层计算逻辑2.1 DPR 到底怎么算出来的DPRDevice Pixel Ratio设备像素比的定义很简单设备的物理像素数除以 CSS 逻辑像素数。浏览器里直接访问window.devicePixelRatio就能拿到当前设备的值。举几个真实例子iPhone 6/7/8逻辑分辨率 375×667物理分辨率 750×1334DPR2iPhone 14 Pro逻辑分辨率 393×852物理分辨率 2556×1179DPR3主流 Android 旗舰DPR 一般为 2.5~3.0部分折叠屏或 2K 屏安卓机DPR 可到 3.5 甚至 4.0这就意味着“一套设计到处跑”这件事在图片资源上是行不通的。同样是 375 宽的逻辑视口DPR2 的手机需要 750 物理像素宽的图片DPR3 的手机就需要 1125 物理像素宽的图片。如果你只准备了一张 750px 的图放到 DPR2 的机型上正好放到 DPR3 的机型上就要被拉大、被插值糊是必然结果。很多人会问为什么电脑上没感觉、手机上一看就糊答案也很简单大部分桌面显示器的 DPR 还停留在 1 或 2手机则普遍是 2.5 到 3 起步高端机型甚至更高。DPR 越高对图片物理分辨率的要求就越苛刻问题自然在移动端暴露得更明显。2.2 图片资源该导多大的一个速算公式我在做前端适配时会用下面这个公式来核验所有位图资源是否合格图片物理像素 ≥ 图片在页面中的 CSS 尺寸 × 目标设备 DPR举例页面里一个 80×80 的 App 图标目标设备 DPR3那么源图至少要 240×240 物理像素。一个全屏背景图CSS 尺寸是 390×844iPhone 14 Pro 的逻辑尺寸DPR3那源图需要 1170×2532 物理像素才能保证整屏不糊。注意这个公式要同时考虑宽和高不要只看宽度。很多人只记得高度和宽度成正比却忘了 Retina 屏幕的物理像素是“宽和高各乘 DPR”总面积是乘 DPR² 的。宽度达标但高度不达标上下边缘一样会虚。2.3 设计软件里的 1x、2x、3x 导出是从这来的很多设计师很好奇为什么开发提资源时动不动要 2x、3x其实就是因为上面这个计算。设计稿里一个 24×24 的图标对应的是它在 375 逻辑宽画布上的 CSS 尺寸。要在 DPR2 和 DPR3 的机器上都清晰就得分别导出 48×48、72×72 的位图。这也是为什么现在的设计工具导出资源时都会让你选 1x、2x、3x而不是一股脑导一个大图——因为不同屏幕密度需要不同规格的资源合理分级才能兼顾清晰度和体积。有一个细节值得多说一句iPhone 6 Plus 这一代机型系统内部按 DPR3 渲染但最终输出到 1080P 物理屏后会再做一次降采样。它的实际渲染 DPR 是 3但物理 DPR 接近 2.6。大多数情况下我们仍然按 3x 出资源因为系统渲染阶段就是按 3x 的。这里不用过度纠结只要记住主流 iOS 高端机型按 3x 准备资源即可。3. 压缩是在丢弃信息关键是要知道丢了什么3.1 有损压缩到底对图片做了什么图片压缩这件事很多人的理解是“把图片变小一点”模糊点说确实没错但它更准确的本质是通过算法丢弃人眼不太敏感的信息换取更小的体积。以 JPEG 为例它会把图像切成一个个 8×8 的像素块做离散余弦变换后人眼对高频细节也就是锐利边缘、纹理细节不敏感于是算法就把高频分量的数值往零的方向“量化”量得越狠文件越小高频信息损失也越多。结果就是文字边缘开始出现毛刺、虚影纹理细节被磨平渐变区域出现色带。WebP 和 AVIF 的编码思路比 JPEG 更先进它们用了更复杂的预测编码和更高级的变换能在同样体积下把高频信息保留得更好。但不管什么有损格式都绕不开一个原则压缩率越高细节丢失越多。没有任何算法能在无限压缩的同时保持无限清晰“又要体积小又要高画质”只能在某个质量拐点附近取得平衡。3.2 什么内容的图最容易被压缩压糊我在项目里踩出来的经验是不同类型的图对压缩的容忍度差别巨大。渐变和光滑表面最容易出现色带banding。比如天空、背景光晕压到质量 50 以下肉眼可见一道一道的颜色断层。文字和 UI 边缘容易出振铃边缘一圈一圈的伪影和模糊。比如带文字的 banner、包含尖锐边角的图标。纹理密集的图片如树叶、布料、头发压缩会把这些纹理“擦”成一片细节全丢。人像皮肤大面积肤色本来就是低频信息压到 60~70 肉眼还能接受但压到 40 以下皮肤会显得“塑料感”十足。所以如果你要压的是一张带大标题文字的营销 banner我建议质量参数给高一点JPEG 或 WebP 85 左右因为文字区域对清晰度的感知极其敏感如果是纯风景摄影背景质量压到 70 左右肉眼几乎分辨不出来。3.3 质量参数 70/80/90 的真实观感差异我在多个项目里做过盲测结论可以参考JPEG 质量参数从 90 降到 80文件体积通常能减少 30%~50%视觉差异在大部分内容上都微乎其微从 80 降到 70体积还能再缩 20%~30%但在文字边缘和渐变区域会开始露出马脚从 70 往下各种伪影就会变得明显。所以我的默认建议是普通内容 JPEG 用 75~85有文字或 UI 元素的图用 85~90仅在确实需要极限压缩时再用 60~70。WebP 的整体表现比 JPEG 好一档。同样视觉质量WebP 的体积常常是 JPEG 的 60%~75%。我自己用 cwebp 压图时质量参数一般给 75~80AVIF 更夸张质量 45~60 就能达到接近 WebP 80 的视觉效果体积能再省 20%~30%。但 AVIF 编码慢、解码开销高低端安卓机上要小心使用不能只管体积不管性能。4. 格式选错清晰度还没开始比就已经输了4.1 JPEG、PNG、WebP、AVIF 的真实应用边界格式选择和“糊不糊”的关系很多人没意识到格式本身不直接决定清晰度但它决定了你在同样的体积预算下能保留多少细节。同一个画面用 JPEG 压到 100KB 可能已经开始发糊用 WebP 压到 100KB 可能还很锐利这就是格式选择的差距。我整理了一张非常适合放在项目 Wiki 里的对比表格式透明通道有损/无损同视觉质量体积兼容性最适合的内容JPEG不支持有损基准所有环境照片、复杂的渐变背景PNG支持无损最大通常比 JPEG 大数倍所有环境图标、UI 元素、需要透明的图形WebP支持两种都支持比 JPEG 小 25%~35%现代浏览器全支持通用替代品日常首推AVIF支持两种都支持比 WebP 再小 20%~30%Safari 16、Chrome 85、Android 12大图、高质量内容能用就用需要特别提醒的是 PNG 的坑它虽然无损但和“清晰”强绑定维护成本也高。一个透明 PNG 图标可能几百 KB换成无损 WebP 能缩小一半以上。现在浏览器对 WebP 支持已经很完备没必要死守 PNG。除非你是在做兼容远古浏览器的企业项目否则新项目里 PNG 应该退出日常图片格式的名单。4.2 根据图片内容决定格式而不是凭习惯同一个页面里不同区域的图片应该用不同格式这是我在多次优化后总结出的比较高效的策略全屏 banner 或大图优先 WebP/AVIF。图片面积大体积敏感这两种格式能帮你省下大量带宽同时保持足够锐利。图标和 UI 元素优先 SVG矢量或 WebP 无损。SVG 不参与像素运算任意 DPR 下都不糊这是位图永远比不了的。如果只能用位图至少用 2x/3x 的 WebP 无损而不是 1x 的 PNG。表情包、聊天图片这类高频小图WebP 有损即可质量 75~80兼容性和体积都合适。需要保留透明通道的复杂图形WebP 无损或 AVIF 无损。这里我想强调一个观点很多人把“格式选择”当成后端或前端的事但决定图片格式的应该是内容本身。一张照片塞进 PNG 是体积灾难一个 UI 图标导出成 JPEG 是质量灾难。搞不清楚内容类型就动手压图事倍功半。4.3 用 picture 标签做渐进增强全都要很多人担心 AVIF/WebP 兼容性办法其实很简单用picture标签做多源回退浏览器会优先选它认识的格式不认识的自动降到 JPEG/PNG。我在移动端项目里的标准写法是这样picture source srcsetbanner-2x.avif 2x, banner-3x.avif 3x typeimage/avif source srcsetbanner-2x.webp 2x, banner-3x.webp 3x typeimage/webp img srcsetbanner-2x.jpg 2x, banner-3x.jpg 3x srcbanner-2x.jpg alt活动主视觉 /picture这样既享受了现代格式的体积和清晰度优势又不会在老旧浏览器上碎图。需要说明的是上面这个写法把 DPR 选择直接写进了srcset的 2x/3x 描述符里浏览器会根据设备密度自动挑最合适的那张。如果图片的展示宽度还会随视口变化那就应该把w描述符和sizes结合起来我下面会细讲。5. 一套能直接落地的图片处理流程从设计稿到手机5.1 设计稿导出阶段的三个关键动作第一个动作确认设计稿基准宽度。如果你的设计稿是 375 宽1x 逻辑尺寸那所有位图资源按 2x、3x 导出即可如果你的设计稿是 750 宽很多团队习惯 2x 起画那导出 1x 就相当于 2x不要被“1x”这个名字带偏。我建议团队里统一一个约定否则每次都要解释一遍。第二个动作能用矢量的用矢量。图标、按钮、装饰线条全部用 SVG 导出不要转成位图。SVG 的好处是整个页面的 DPR 再高都不会变糊文件还特别小。只有照片和复杂位图才需要走下面的位图流程。第三个动作位图按公式计算最小分辨率。先把图片在页面里的实际 CSS 尺寸列出来再乘以目标 DPR一般取最大需要 3 或者 4得到源图物理尺寸。举个实际场景设计稿里有一个 88×88 的逻辑尺寸商品图标目标设备包括 DPR3 的 iPhone那么源图至少导出 264×264 物理像素。很多设计工具可以一键导出 1x/2x/3x这时你导出 3x 即可用于所有高密度屏2x 用于中低密度屏。如果设计稿原始资源达不到这个值要标注出来让设计师重新导出而不是硬着头皮用。这一步做完基本能杜绝大部分“手机上图片糊”的问题。5.2 压缩工具选型与一套可复用的参数压缩环节我给自己的工具箱和参数如下都是亲测过稳定可用的Squoosh免费在线工具直接在浏览器里对比原图和压缩后的细节支持 JPEG/WebP/AVIF。适合一张一张精修。TinyPNG在线批量压缩适合对 PNG/WebP 做无脑批量处理但不能细调质量。ImageOptimmacOS 本地批量压缩适合团队统一处理素材配置一次后拖拽即可。命令行工具集成到 CI 流水线时用。cwebp、avifenc、cjpeg 分别对应 WebP、AVIF、JPEG。示例# 导出 WebP质量 80 cwebp -q 80 banner.png -o banner.webp # 导出 AVIF质量范围 40~50 avifenc --min 40 --max 50 banner.png -o banner.avif # 导出 JPEG质量 82 cjpeg -quality 82 banner.png -o banner.jpg参数方面我的通用基准是JPEG 75~85WebP 有损 75~80AVIF 45~60。如果图片里有大段文字质量往上调 5~10。如果只是背景纹理适当往下降。压缩这件事没有唯一正确答案最终判断标准是“在同一台 Retina 屏幕上原图和质量图并排放大到 200% 对比肉眼无明显差异”。另外如果你是在做 H5 上传图片的交互前端用 canvas 压缩后再上传也是完全可行的方案。核心是生成 canvas 时先按目标显示宽度 × DPR设置画布尺寸再调canvas.toBlob()指定质量参数最后把 blob 塞进 FormData 上传。但要注意前端压缩不能替代服务端转码它更适合解决“用户手机原图 10MB直接上传太慢”这类场景。5.3 前端适配srcset、sizes 和 CSS 的一整套配合图片资源准备好之后前端要用正确的方式加载。很多模糊问题其实出在加载方式上——浏览器把图硬拉到了不该放的尺寸。对于需要响应屏幕宽度的图推荐srcsetsizes的写法让浏览器自己根据视口宽度和设备 DPR 选图img srcsetbanner-400.jpg 400w, banner-800.jpg 800w, banner-1200.jpg 1200w sizes(max-width: 480px) 100vw, 800px srcbanner-800.jpg alt活动主视觉 /这里的400w表示图片资源宽 400 物理像素sizes告诉浏览器这个图片在页面里实际占多宽。浏览器会结合当前视口宽度和 DPR 计算出真正需要的图片宽度然后从候选里挑最合适的那张。如果我们只给一个srcbanner-800.jpg那么在 DPR3 的大屏手机上800px 的图可能不够糊的局面又会出现。对于作为 CSS 背景图的场景可以用 image-set() 按 DPR 提供不同资源或者直接把多倍图信息写进 CSS.banner { background-image: image-set( banner-1x.jpg 1x, banner-2x.jpg 2x, banner-3x.jpg 3x ); }注意即便是背景图源图本身的分辨率依然要先满足“CSS 尺寸 × DPR”这个条件image-set 只是负责把选图逻辑自动化不负责无中生有。5.4 验收从模拟器到真机把“糊不糊”变成可判断的标准最后的验收环节我把它分成三步。第一步在 Chrome DevTools 的 Device Mode 里把 DPR 手动设成 2 和 3分别看页面图片资源是否加载了对应的 2x/3x 版本。第二步再用 Network 面板确认实际加载的图片 URL 的分辨率和显示尺寸做换算。第三步真机看一遍尤其要看首页 banner、轮播图、商品图这类大图区域。模拟器能模拟逻辑像素和 DPR但模拟不了真实屏幕的观感所以真机这步省不得。我常用的一个技巧是在页面里临时给图片加outline: 1px solid red如果图片被 CSS 拉得明显超出原分辨率红色框内会出现模糊接着用document.querySelector(img).naturalWidth查看图片原始物理宽度和clientWidth * devicePixelRatio对比就能快速定位是资源问题还是加载方式问题。这个方法可以分享给所有做移动端的朋友。6. 排查清单遇到“图糊了”按这个顺序找原因6.1 最常见的几种“糊”和它们的真凶我在帮团队排查图片模糊问题时总结出一个比较高效的排查顺序按照出现频率从高到低排现象最可能的原因解决方向全屏背景图边缘发虚源图分辨率不够 显示尺寸×DPR重新导出 2x/3x 资源或提高源图宽度图标/小图糊用了 1x 位图或没有 3x换 SVG或导出 3x 位图文字边缘马赛克压缩质量压太低JPEG/WebP 质量提到 85图片在某种机型糊另一种不糊DPR 差异导致高 DPR 机型不够吃按高 DPR 机型准备资源图片被人为拉伸CSS 设置了固定宽高比例不匹配检查 CSS width/height、aspect-ratio加载时先模糊后清晰或一直模糊懒加载占位图/低质量预览图被当最终图检查懒加载的真实图片 URL 是否正确原图清晰上线后部分设备变糊CDN 在分发时自动转码成低质量版本关闭 CDN 图片压缩或调高转码质量6.2 一条排查链路从一个 banner 糊的案例说起有一次线上反馈首页 banner 在 iPhone 14 Pro 上发糊我先看 Network 里实际加载的图URL 末尾是banner_640.jpg640px 宽。再看页面里这个 banner 的 CSS 尺寸是width: 100%在 390 逻辑宽的手机上DPR3浏览器期望的物理宽度是 390×31170px。而实际只有 640px等于少了将近一半的像素信息。问题定位就清晰了不是压缩太狠也不是格式问题是源图分辨率没匹配上 DPR。后来把资源换成了 1170px 宽的 WebP文件体积反而比原来的 640px JPEG 还小画质却明显上一个台阶。这个案例里最值得学习的一点是分辨率不足导致的糊靠压缩优化是救不回来的。你只能提升源图物理像素。压缩能做的事情是在“分辨率足够”的前提下控制体积两者的关系一定要分清。写到这里差不多把 DPR、压缩、格式选择这条链路讲透了。如果只记住一条经验我希望是这句话先在源头上保证图片物理分辨率达标再去考虑压缩和格式反过来再好的格式也补不了像素缺失的坑。以后你再看设计稿别轻易用肉眼说“这张图很清晰”先算算它的物理分辨率能不能喂饱目标手机的 DPR再决定压不压、用什么格式压。这才是真正不再被“糊”困扰的开始。
返回列表