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

96
凌霄光
0.1 2017.08.24 14:39* 字数 2225

在开发中,我们常用的几个尺寸的单位,就是px,rem,微信小程序中会用到rpx,可能你不理解它们的关系也能用起来,但想避过与单位有关的一些坑,你就得深入理解他们。

px和物理像素

显示的原理就是把要显示的数据写入显存区域,然后显示设备读取这些数据,驱动硬件就可以显示了。显示的数据是以像素为单位的,一个像素只能显示一种颜色,但是根据显示颜色的总数不同,每个像素占的位数也不同。如果我想显示黑白,那一位就可以存储了,但如果我想显示16种颜色,就得4位来存储一个颜色,这样的一个存储单位就叫做物理像素

我们写样式时一个像素记作1px,但是css的px和物理像素是一一对应的吗,是同样的概念么?在pc端是这样的,因为屏幕足够大,一个css像素用一个物理像素来显示,完全可以,pc端默认情况下一个css像素就对应着一个物理像素,但是有没有发现你把分辨率调小以后,显示的内容变大了,但是显示器的物理像素肯定不会变啊,这时候其实就是一个css像素对应着若干个物理像素了,这个是与用户设置有关。

移动设备大小是有限的,而且分辨率不低,甚至比pc端更高,也就是可以显示的物理像素更多,如果和pc端一样,一个css的px和物理像素一一对应,可以想象,显示的内容有多小。这样肯定是不行的,解决这个问题,我们可以很自然的想到,那在移动设备上就别一一对应了,一个css的px对应多个物理像素吧,这样就不至于显示的内容过小了,实际上移动设备也是这么做的,你在开发时写的px和最终渲染显示的物理像素数不是一比一的,可能一个px对应2个物理像素,可能3个物理像素,设备显示的物理像素数和你css的px数的比值就叫做设备像素比(device pixel radio),简称dpr。好了,这样显示内容过小的问题就解决了。

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

rem和rpx

rem

移动设备的宽度是各种各样的,每个设备的dpr也不同,换句话说就是不同设备每一行的物理像素数不同,能显示的css的px数也不同,如果我们写死px的话,那么后果就是同样的px,在不同设备中显示的行数不同,这样整个排版就乱了,想想有啥解决的思路没?

分析一下造成显示效果不同的原因就是设备宽度不同,你可能会问,那dpr呢,其实与dpr一点关系都没有,想象一下2个宽度为1000个物理像素的设备,一个dpr为1,一个dpr为2,那么在我们看来不过一个是1000px,一个是500px而已,在这里我们感知不到dpr。那么设备宽度不同怎么做适配呢,其实很容易的会想到,每个设备每行显示的px数不同,你写死px数的话,那肯定显示的效果不一样,所以,不能写死,要动态的计算。对,实际上也是这么解决的,那怎么计算呢,很简单,你把一个设备的样式写好了,其他的根据设备的宽度(px数)的比,来动态计算就行了。

rem就是解决这个问题的,rem不是具体的px,rem具体显示多少像素,是根据根元素的font-size来计算的,比如说你设置了1.2rem,根元素的font-size是100px,那么这个元素动态算出来的px数就是120px。不同宽度,设置不同px,这样就可以适配所有宽度的设备了。看一下实际开发中我们动态计算根元素font-size的代码:
先来个伪代码:

   var  根元素fontsize =  实际设备宽度 / 开发时设备宽度  * 开发时根元素font-size

具体代码是:(假设开发时我们适配的是iphone6,也就是375px的设备,我们开发时根元素font-size设为了100px)

   document.documentElement.style.fontSize =
 (document.documentElement.offsetWidth/375)*100 + 'px' ;

这样就可以了,其实我们还可以再除以2,为什么呢,因为我们现在设计稿量出来的是物理像素,iphone6的dpr是2,我们要把量出来的数除以2,就是实际的px,然后再除以100,就是rem,既然每次都要这么做,为什么不在根元素这里把除以2给统一做了,只需要把量出的数只要除以100就是rem了。挺完美,现在基本也是用的这种方案。

其实除了根据设备宽度比例计算具体px还有一种思路,我们可以根据设备宽度不同,给不同元素设置不同的px不就行了,这也是一种思路,媒体查询可以做到这个,也有些网站是这么做的,但是这样不能兼顾所有的设备,因为你不可能设置很多套样式,只会在关键的几个设备宽,设置几套,而动态计算的方式,可以适配所有的宽度。

rpx

微信小程序开发时用的是前端的技术,类似html的组件标签,css,js,他面临的问题和网页一样,就是不同宽度的设备的适配,解决思路当然也是一样,但是有一点不同的是不能用rem,为什么呢,因为根本就没有html元素啊,咋解决,很简单,我不基于html的font-size了,我基于一个别的值就行了,你也不需要计算这个值,我给你计算了,这就是rpx。最终的效果就是,你开发时在iphon6的设计稿上量了多少px,就写多少rpx就行了,完美适配,perfect!

一些坑

其实这个看似完美的方案也会带来一些问题,比如说,我根据rem乘以根元素font-size算出的px值有小数,最终是零点几px咋办,不同浏览器对这个支持程度不同,有的只渲染出零点几px对应的物理像素,有的干脆都显示1px,后果就是,同样的rem值,在不同dpr的设备上宽度不同,最常见的就是边框,有的设备上显得特宽,特别扭,也就是经典的1px边框问题。这个问题的解决方案也有很多,可以通过设置1px,然后根据不同dpr,设置不同的缩放来做,当然也有其他的方案。我这里只是想说rem带来的一些问题。

像素比和宽度比

像素比:dpr是设备像素比,也就是css的设备无关像素px和物理像素的比
宽度比:开发适配的设备的宽度(现在一般是iphone6),和实际的设备的宽度的比
总的来说,可以一句话来总结,像素比实现高清,宽度比实现适配

Web note ad 1