移动端适配问题

一、首先解释几个概念

物理像素(physical pixel)

一个物理像素是显示器(手机屏幕)上最小的物理显示单元,在操作系统的调度下,每一个设备像素都有自己的颜色值和亮度值。

设备独立像素(density-independent pixel)

设备独立像素(也叫密度无关像素),可以认为是计算机坐标系统中得一个点,这个点代表一个可以由程序使用的虚拟像素(比如: css像素),然后由相关系统转换为物理像素。 所以说,物理像素和设备独立像素之间存在着一定的对应关系,这就是接下来要说的设备像素比。

设备像素比(device pixel ratio )

设备像素比(简称dpr)定义了物理像素和设备独立像素的对应关系,它的值可以按如下的公式的得到:

1
设备像素比 = 物理像素 / 设备独立像素 // 在某一方向上,x方向或者y方向

你在开发时写的px和最终渲染显示的物理像素数不是一比一的,可能一个px对应2个物理像素,可能3个物理像素,设备显示的物理像素数和你css的px数的比值就叫做设备像素比(device pixel radio),简称dpr。

在javascript中,可以通过window.devicePixelRatio获取到当前设备的dpr。

在css中,可以通过-webkit-device-pixel-ratio,-webkit-min-device-pixel-ratio和 -webkit-max-device-pixel-ratio进行媒体查询,对不同dpr的设备,做一些样式适配(这里只针对webkit内核的浏览器和webview)。

有了dpr之后,有一个问题就是同样的一张图片,我设了宽高的px数,那么在dpr为1的设备上,和dpr为2的设备上显示的效果是一样的,1个px在dpr为1的设备上会用1个物理像素来显示,在dpr为2的设备上会用2*2个物理像素来显示,这样dpr高的优势就体现不出来了,我设备比他的好,你给我的体验是一样的,可能有些用户不爽,我们可以区分对待,对于高dpr的设备,用物理像素更多的高清图片来替代,也就是2x图,3x图等等。

什么是2x图片?

2x图片是指比原图尺寸大一倍的图片
这样在css尺寸不变的情况下,就能用到更多的物理像素来显示图片。

二、适配问题

考虑移动端适配问题的时候,不需要管物理像素以及dpr等,只管css像素。只跟下图中的逻辑分辨率有关。

为什么需要做移动端适配?

因为不同的手机,每一行能显示的css像素总数是不同的。
比如
iphone5能显示的css像素尺寸为320 x 568
iphone6能显示的css像素尺寸为375 x 667

如果宽度写死为320px,在iphone5下是占满整行的,但是在iphone6下确没有满整行。

rem就是解决这个问题的,rem不是具体的px,rem具体显示多少像素,是根据根元素的font-size来计算的,比如说你设置了1.2rem,根元素的font-size是100px,那么这个元素动态算出来的px数就是120px。

适配方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<script>
let doc = window.document
let baseWidth = 750 // 这里是根据设计稿的尺寸来的
let documentHTML = doc.documentElement
let pixelRatio = 2

function setRootFont () {
let docWidth = documentHTML.getBoundingClientRect().width
let scale = docWidth / baseWidth
let setSize = scale * 100
documentHTML.style.fontSize = setSize + 'px'
let realSize = parseFloat(global.getComputedStyle(document.documentElement).fontSize, 10)
// android webview 里 html font-size 因设置系统字体大小受到影响
if (realSize != parseFloat(setSize.toFixed(4), 10)) {
setSize = (setSize * setSize) / realSize
documentHTML.style.fontSize = setSize + 'px'
}
// 设置data-dpr属性,留作的css hack之用
pixelRatio = global.devicePixelRatio === 3 ? 3 : 2
documentHTML.setAttribute('data-dpr', pixelRatio)
}

setRootFont()
window.addEventListener('resize', setRootFont, false)
</script>

工程中加入postcss-pxtorem

1
npm install postcss-pxtorem -D

项目中增加配置

1
2
3
4
5
6
extraPostCSSPlugins: [
pxtorem({
rootValue: 100,
propWhiteList: [],
}),
],

配置项参考
postcss-pxtorem

上面的baseWidth是根据设计稿的尺寸来的设置的,如果设计稿是750,那么就设置为750,这样设计稿上如果是300px的元素,css样式也直接写300px,通过postcss-pxtorem插件,自动转化为3rem。
如果在ihone6下,font-size: 50px
计算之后的实际像素为

1
3rem * 50px = 150px

150px在iphone6屏幕下差不多占一半宽,而300px在设计稿上也差不多占一半宽

像素比和宽度比

像素比:dpr是设备像素比,也就是css的设备无关像素px和物理像素的比

宽度比:开发适配的设备的宽度(现在一般是iphone6),和实际的设备的宽度的比

总的来说,可以一句话来总结,像素比实现高清,宽度比实现适配

如何在高清屏幕下实现1px像素?

通常可以设置元素after或before伪元素为1px,并使用

1
transform: scaleY(1/devicePixelRatio)

来进行单方向的缩放实现1个物理像素的边框或内容。

此外对于字体,我们也可以设置

1
transform: scale(0.5)

来显示小于12px的文字

如果页面内容因为高清屏而导致模糊,则可以使用

1
-webkit-font-smoothing: antialiased

来尝试修复

参考资料

px、物理像素、rem、rpx的关系

从设备像素比到移动适配

物理像素和逻辑像素


移动端适配问题
https://thaneyang.github.io/2019/07/移动端适配问题.html
作者
ThaneYang
发布于
2019年7月3日
许可协议