移动端自适应基础

1,249 阅读8分钟

基础知识

物理像素(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 的存在,相同大小的文字,看起来会更加清晰。下文会进一步解释这个概念。

image.png

屏幕分辨率与设备独立像素(Device Independent Pixel)

在手机上,需要引入一个新的概念:屏幕分辨率。以 iPhone 8 为例,通过截图就能轻易发现,实际的屏幕分辨率是 750 × 1334,与物理像素是相同的。

为了兼容不同大小的屏幕,屏幕分辨率和 DPR 之间的关系涉及到一个专用的概念,设备独立像素(也叫密度无关像素),简称 dip,可以认为是一个抽象的像素,DPR 越高,这个像素由越多的物理像素绘制,也就是前文提到的等效的概念。还是以 iPhone 8 为例,在短边拥有 375 个 dip,也就是等效 css 中的 375px。

下表整理了历年 iPhone 机型,帮助加深理解。

物理像素屏幕分辨率DPR设备独立像素
iPhone 3GS320 x 480320 x 4801320 x 480
iPhone 4640 x 960640 x 9602320 x 480
iPhone 8750 × 1334750 × 13342375 × 667
iPhone 8 Plus1080 x 19201242 × 22083414 × 736
iPhone X1125 x 24361125 × 24363375 × 812
iPhone 11828 x 1792828 × 17922414 × 896
iPhone 13 mini1080 x 23401125 × 24363375 × 812
iPhone 13 Pro1170 x 23521170 × 25323390 × 844
iPhone 13 Pro Max1284 x 27781284 × 27783428 × 926

通过上述分析,再来补充前文关于 DPR 的论述。

在相同面积内,用倍数的物理像素进行绘制,这个倍数就被称为 DPR。

现在可以在整块屏幕的尺度来解释为什么同样的 27 寸 4K 显示器设置 200% 缩放后比 1080P 显示器,文字显示更加清晰。这是因为设置 200% 缩放就是设置了 DPR 为 2,此时的看起来和 1080P 显示器的内容容量是一致的,但在物理像素层面,每个 dip 都由 4 个物理像素绘制,是原来的四倍,所以看起来更加清晰。

Untitled 1.png

细心的小伙伴可能发现了,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。这样可以轻松兼容不同的屏幕尺寸,宽屏幕上内容看起来大些,窄屏幕上内容看起来小些。

但其中隐含了这种设计的局限性。

  1. 设计师的画板被限死在 750px,DPR 2。因为只有这样,rpx 和 px 的换算才是事实上可行的,有谁会想和一堆小数打交道呢。
  2. 当屏幕宽度超出某个范围,比如在 iPhone 5 或者在 iPad 上打开小程序,rpx 体系下的内容就会过小,或者过大。也就是说,rpx 所谓的自适应,是一定范围内的自适应。

H5 自适应分析

css 3 中有两个新的单位 rem 和 em。大家都不喜欢 em,就只谈谈 rem 吧。

简单说,rem 是以根节点 font-size px 值作为基准,定义为 1rem。常用的做法是配合查询语句,可以做到根据屏幕大小操控所有以 rem 为单位的元素大小。具体怎么用相关文章也够多了,不赘述了。

rem 和 rpx 的效果是一致的,都是等比缩放,做个对比可以发现 rem 的触发条件是可以编程的,这部分复杂度,使 rem 在我看来是个更完备的自适应方案。

remrpx
变化基准根节点 font-sizedip 宽度
触发条件宽度改变或其他条件(自定义)宽度改变
影响范围全局使用 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/…

www.ayqy.net/blog/完全理解px…

www.cnblogs.com/lovesueee/p…

developers.weixin.qq.com/miniprogram…

zhuanlan.zhihu.com/p/55826586