基础知识
物理像素(Physical Pixel)
设备屏幕硬件上实际的物理像素数量,也称设备像素(Device Pixel),比如 iPhone 8 的设备像素为 750 x 1334,4K 显示器的物理像素为 3840 x 2160。
设备像素比(Device Pixel Ratio)
设备像素比简称 DPR,指用倍数的像素去绘制,在高分辨率下使内容看起来更加清晰。
此处以 4K 显示器,设置 200% 缩放举例。用过的小伙伴肯定就知道了,等效 1080P。
在电脑浏览器控制台里输入以下指令获得当前的屏幕分辨率和 DPR。
console.log(screen.width)
// Output: 1920
console.log(screen.height)
// Output: 1080
console.log(window.devicePixelRatio)
// Output: 2
等效的意思是内容容量不变。因为 DPR 的存在,相同大小的文字,看起来会更加清晰。下文会进一步解释这个概念。
屏幕分辨率与设备独立像素(Device Independent Pixel)
在手机上,需要引入一个新的概念:屏幕分辨率。以 iPhone 8 为例,通过截图就能轻易发现,实际的屏幕分辨率是 750 × 1334,与物理像素是相同的。
为了兼容不同大小的屏幕,屏幕分辨率和 DPR 之间的关系涉及到一个专用的概念,设备独立像素(也叫密度无关像素),简称 dip,可以认为是一个抽象的像素,DPR 越高,这个像素由越多的物理像素绘制,也就是前文提到的等效的概念。还是以 iPhone 8 为例,在短边拥有 375 个 dip,也就是等效 css 中的 375px。
下表整理了历年 iPhone 机型,帮助加深理解。
| 物理像素 | 屏幕分辨率 | DPR | 设备独立像素 | |
|---|---|---|---|---|
| iPhone 3GS | 320 x 480 | 320 x 480 | 1 | 320 x 480 |
| iPhone 4 | 640 x 960 | 640 x 960 | 2 | 320 x 480 |
| iPhone 8 | 750 × 1334 | 750 × 1334 | 2 | 375 × 667 |
| iPhone 8 Plus | 1080 x 1920 | 1242 × 2208 | 3 | 414 × 736 |
| iPhone X | 1125 x 2436 | 1125 × 2436 | 3 | 375 × 812 |
| iPhone 11 | 828 x 1792 | 828 × 1792 | 2 | 414 × 896 |
| iPhone 13 mini | 1080 x 2340 | 1125 × 2436 | 3 | 375 × 812 |
| iPhone 13 Pro | 1170 x 2352 | 1170 × 2532 | 3 | 390 × 844 |
| iPhone 13 Pro Max | 1284 x 2778 | 1284 × 2778 | 3 | 428 × 926 |
通过上述分析,再来补充前文关于 DPR 的论述。
在相同面积内,用倍数的物理像素进行绘制,这个倍数就被称为 DPR。
现在可以在整块屏幕的尺度来解释为什么同样的 27 寸 4K 显示器设置 200% 缩放后比 1080P 显示器,文字显示更加清晰。这是因为设置 200% 缩放就是设置了 DPR 为 2,此时的看起来和 1080P 显示器的内容容量是一致的,但在物理像素层面,每个 dip 都由 4 个物理像素绘制,是原来的四倍,所以看起来更加清晰。
细心的小伙伴可能发现了,iPhone 8 Plus 与 13 mini 的物理像素和屏幕分辨率怎么不一样呀,这个问题的答案留在文末。
实际应用
说了这么多,对于开发者和设计师而言,只需要关心设备独立像素 dip 以及设备像素比 DPR 两个知识点就够了。
此 px 非彼 px
前文涉及到单位的地方几乎都留了空,这是为什么呢?
因为不同语境下,相同的词往往有不同的含义,比如 css 中的 px 和屏幕截图中的长度单位 px 并非相同的概念。前者指的是设备独立像素,而后者指 100% 显示时需要物理像素的数量。。
设计稿
如果要出移动端的设计稿,首先要选取一款手机的屏幕分辨率的宽度作为基准。
对比上表和 iPhone 的发布周期就会发现,从 iPhone 6 到 iPhone 12 发布的六年间,dip 宽度组合一直都是 320、375 和 414。此后销售的 iPhone 宽度都是 375、390 和 428。
由此看来,当下如果想覆盖尽可能多的老机型,375 就是很合适的基准。而如果想给新用户带来更好的体验以及战未来的话,则可以把基准设为 390。
选择完基准后,就要选择 DPR 了,没有设计师想在一块不到 400 的画布上创作低清设计稿吧。虽然不同手机 DPR 各有不同,但是在实际应用中,为了计算方便,一般会选择 2。
css 中 1px 边框问题
首先是老生长谈的 1px 边框问题,在了解了 DPR 的概念之后,就可以明白这其实是很简单的小问题。设计稿上 1px,是以 750px 为参照系的。对应到手机上,实际宽度应该是 0.5px。
具体的解决方法各有利弊,相关文章已经够多了,就不赘述了。
小程序 rpx 分析
小程序使用的标准尺寸单位是 rpx,看过小程序文档的应该对下面这段都不陌生。为了避免歧义,首先需要对概念进行对齐。屏幕宽度,按照本文的上下文,对应的是短边的 dip 数。
rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
由这段话可以看出小程序的解决方案是将屏幕宽度进行 750 等分,并定义 1 份为 1rpx。这样可以轻松兼容不同的屏幕尺寸,宽屏幕上内容看起来大些,窄屏幕上内容看起来小些。
但其中隐含了这种设计的局限性。
- 设计师的画板被限死在 750px,DPR 2。因为只有这样,rpx 和 px 的换算才是事实上可行的,有谁会想和一堆小数打交道呢。
- 当屏幕宽度超出某个范围,比如在 iPhone 5 或者在 iPad 上打开小程序,rpx 体系下的内容就会过小,或者过大。也就是说,rpx 所谓的自适应,是一定范围内的自适应。
H5 自适应分析
css 3 中有两个新的单位 rem 和 em。大家都不喜欢 em,就只谈谈 rem 吧。
简单说,rem 是以根节点 font-size px 值作为基准,定义为 1rem。常用的做法是配合查询语句,可以做到根据屏幕大小操控所有以 rem 为单位的元素大小。具体怎么用相关文章也够多了,不赘述了。
rem 和 rpx 的效果是一致的,都是等比缩放,做个对比可以发现 rem 的触发条件是可以编程的,这部分复杂度,使 rem 在我看来是个更完备的自适应方案。
| rem | rpx | |
|---|---|---|
| 变化基准 | 根节点 font-size | dip 宽度 |
| 触发条件 | 宽度改变或其他条件(自定义) | 宽度改变 |
| 影响范围 | 全局使用 rem 的元素 | 全局使用 rpx 的元素 |
| 如何变化 | 等比缩放 | 等比缩放 |
React Native 自适应分析
因为 React Native 是跨平台的,iOS 的像素单位是 pt,Android 的像素单位是 dp,所以写书写的时候是无单位的。那么 RN 项目是如何做到适配不同屏幕尺寸和分辨率的呢?
答案是,React Native 只负责转换单位,但并没有现成的自适应方案,需要我们自己设计。
结合项目的经验,并参考了一些业界方案,大体情况下,适配可以分成以下几种情况:
- 固定尺寸(按钮、文字大小、间距)
- 保持宽高比(比如banner图片)
- 间距固定,内容自适应(比如产品卡片宽度)
- 按屏幕等比缩放
拓展阅读
不等价的物理像素和屏幕分辨率
以 iPhone 8 Plus 为例,物理像素是 1080 x 1920,但通过截图就能轻易发现,实际的屏幕分辨率是 1242 x 2208,两者并不相符。这种物理像素与屏幕分辨率之间的差异,是为了保持 DPR 是整数 3,由系统自动抹平的。同样的,Mac 电脑在不同分辨率下,为了保持 DPR 为 2 的 Retina 显示,也存在这种关系。Windows 电脑和 Android 手机由于屏幕尺寸更多,这种不等价关系更加突出,DPR 也不一定是整数。
结语
最近居家办公比较空闲,学习自适应适配的过程中发现不同语境下,相同词汇概念可能天差地别,很多文章中引入了非必要的信息,也容易造成误解。于是针对这一现象,结合自己的思考,形成了这篇文章。行文仓促,敬請不吝斧正。自适应适配的具体方法在所有端都是通用的,之后有时间再写文章。
参考
developer.mozilla.org/en-US/docs/…