4、分辨率与密度适配:Android的mdpi/hdpi/xhdpi/xxhdpi/xxxhdpi、iOS的@1x/@2x/@3x、Web的响应式图片

做界面移植,最头疼的问题是什么?

我个人觉得,就是同一张图在不同设备上「忽大忽小、忽糊忽清」。你想想看,设计师给你一张 1080×1920 的图,你往 iPhone 4 上一放,撑爆了;往 iPad Pro 上一放,又虚得像马赛克。

这背后其实就两个核心概念:分辨率和密度。很多人把它们混为一谈,但它们是两码事。分辨率是像素总数,密度是每英寸有多少像素。搞清楚这个,适配就成功了一半。

核心公式:

物理尺寸 = 分辨率 ÷ 密度

同一张图在不同密度设备上,物理尺寸会变。适配的本质,就是让图片在不同密度下保持一致的物理观感。

4.1 Android 的密度体系:从 mdpi 到 xxxhdpi

Android 的碎片化是出了名的。我记得刚入行那会儿,公司测试机有二十多台,屏幕密度从 160dpi 到 640dpi 都有。Google 为了统一管理,搞了一套密度桶:mdpi、hdpi、xhdpi、xxhdpi、xxxhdpi。

每个桶对应一个基准密度,缩放因子是固定的:

密度限定符 基准密度 (dpi) 缩放因子 常见设备举例
mdpi 160 1× 早期 3.7 寸手机
hdpi 240 1.5× HTC Desire、小米 1
xhdpi 320 2× Galaxy S3、小米 2
xxhdpi 480 3× Galaxy S5、小米 4
xxxhdpi 640 4× Galaxy S8+、小米 6

实际项目中怎么用?我一般这样操作:

  • 设计师给一张 48×48dp 的图标,对应 mdpi 就是 48×48px。
  • 放到 hdpi 目录下,图片尺寸要变成 48×1.5 = 72px。
  • 放到 xhdpi 目录下,就是 48×2 = 96px。
  • 以此类推。

我的习惯:如果只给一套图,我会选 xxhdpi(3×)作为基准。因为向下缩放比向上放大清晰,而且现在主流设备基本都在这个档次以上。

4.2 iOS 的 @1x / @2x / @3x

iOS 这边就清爽多了。从 iPhone 4 开始引入 Retina 屏,苹果搞了 @2x;iPhone 6 Plus 之后又加了 @3x。说白了,就是物理像素和逻辑像素的倍数关系。

  • @1x:非 Retina 屏,1 个逻辑点 = 1 个物理像素。iPhone 3GS 及以前。
  • @2x:Retina 屏,1 个逻辑点 = 2×2 个物理像素。iPhone 4/5/6/7/8 等。
  • @3x:超 Retina 屏,1 个逻辑点 = 3×3 个物理像素。iPhone 6 Plus/7 Plus/8 Plus/X 及以后。

举个例子:设计师说图标是 24pt × 24pt。

  • @1x 图:24×24px
  • @2x 图:48×48px
  • @3x 图:72×72px

命名规则也很简单:icon.png、icon@2x.png、icon@3x.png。Xcode 会自动根据设备选择对应倍率的图。

我曾经踩过的坑:iOS 的 @3x 图不能简单地把 @2x 图放大 1.5 倍。因为 @3x 的物理像素是 3 的倍数,而 @2x 是 2 的倍数,直接缩放会导致边缘锯齿。最好让设计师单独导出 @3x 资源。

4.3 Web 的响应式图片

Web 端的情况更复杂。没有统一的密度体系,全靠 CSS 和 HTML 自己控制。我早期做 Web 移植时,经常被设计师问:「为什么我的图在 4K 屏上这么糊?」

Web 的适配主要靠三个东西:

4.3.1 srcset 属性

告诉浏览器不同分辨率下用哪张图:

<img src="photo-1x.jpg"
     srcset="photo-2x.jpg 2x,
             photo-3x.jpg 3x"
     alt="示例图片">

浏览器会根据设备像素比(DPR)自动选择。DPR = 2 的设备,就加载 photo-2x.jpg。

4.3.2 sizes + srcset 组合

这个更灵活,适合响应式布局:

<img src="photo-400.jpg"
     sizes="(max-width: 600px) 100vw,
            (max-width: 1200px) 50vw,
            33vw"
     srcset="photo-400.jpg 400w,
             photo-800.jpg 800w,
             photo-1200.jpg 1200w"
     alt="响应式图片">

sizes 告诉浏览器图片在布局中占多大空间,srcset 提供不同宽度的候选图。浏览器会结合设备宽度和 DPR 选最合适的。

4.3.3 picture 元素

适合艺术指导(Art Direction)场景——不同屏幕用不同裁剪或构图的图片:

<picture>
  <source media="(min-width: 1200px)" srcset="hero-desktop.jpg">
  <source media="(min-width: 768px)" srcset="hero-tablet.jpg">
  <img src="hero-mobile.jpg" alt="横幅图片">
</picture>

注意:<img> 标签必须保留,作为兜底。

我的建议:Web 端不要只给一套图。至少准备 1× 和 2× 两套。3× 看项目预算。现在 MacBook Pro 和高端显示器都是 2× 起步,只给 1× 图会显得很业余。

4.4 三端对比:一张表说清楚

维度 Android iOS Web
密度单位 dpi(每英寸点数) PPI(每英寸像素) DPR(设备像素比)
基准倍数 1× (mdpi) 1× (非 Retina) 1× (传统屏)
常见倍数 1.5× / 2× / 3× / 4× 2× / 3× 2× / 3×
资源命名 目录区分(drawable-xhdpi) 文件名后缀(@2x) srcset / picture
适配方式 系统自动匹配密度桶 系统自动选 @2x/@3x 浏览器根据 DPR 和视口选择

4.5 移植时的实操建议

做界面移植时,我一般按这个流程走:

  1. 先确认设计稿的基准密度。Sketch 默认是 @2x,Figma 可以调。问清楚再动手。
  2. 统一换算成逻辑单位。Android 用 dp,iOS 用 pt,Web 用 CSS px。这三者在数值上可以近似等同(1dp ≈ 1pt ≈ 1px 在 160dpi 下)。
  3. 按目标平台生成对应倍率的图。不要手动缩放,用工具(如 Sketch 的切片导出、TinyPNG 批量处理)。
  4. 测试要覆盖低密度设备。我见过太多人只测旗舰机,结果图在低端机上要么溢出要么模糊。

避坑指南:我曾经接手过一个项目,Android 端只放了 xxhdpi 的图,结果在 mdpi 的平板上,系统把 3× 图强行缩到 1×,内存占用飙升,直接 OOM 崩溃。所以,关键图片至少准备 mdpi、hdpi、xhdpi 三套,别偷懒。

4.6 知识体系总览

下面这张图把三端的密度适配逻辑串起来了。你可以把它当作移植时的「地图」:

分辨率与密度适配知识体系 分辨率与密度适配知识体系 图片密度适配 Android 密度桶 iOS @倍数 Web 响应式图片 mdpi (1×) hdpi (1.5×) xhdpi (2×) xxhdpi (3×) xxxhdpi (4×) @1x @2x @3x srcset sizes picture 核心原则 逻辑单位统一 → 按倍数生成资源 → 系统/浏览器自动选择

嗯,这张图把三端的适配逻辑都串起来了。你移植的时候,先确定目标平台的密度体系,再按倍数生成资源,最后交给系统或浏览器去选。说白了,就是「逻辑统一、物理分倍」这八个字。