前端开发,遇到的最常见的对象应该就是屏幕了,在一块指定的屏幕上展示想要展示的内容,是前端的本质和基础。
对于一块指定的屏幕,它有的固定不变的东西,就是 屏幕像素 了,它是这块屏幕能够完成渲染的最小单元,一块屏幕拥有的屏幕像素的个数,就是 屏幕分辨率。比如,iphone6的屏幕分辨率为750 * 1334,这意味着这块屏幕的宽有750个屏幕像素点,高有1334个屏幕像素点;而我手上的iphone xs max的屏幕分辨率为1242x2688。
最简单的开发,是面向设备分辨率的开发,但是这样就会面临一个问题。比如绘制的一个元素是750个屏幕像素的宽度,我们期望它在iphone6上展示的是一个宽度撑满整个屏幕的元素,但是若是iphone6为了某个原因,出了一个升级款iphone6 ppplus,屏幕的尺寸没有变化,但是在设备分辨率上做了升级,宽度变成了1125=375x3个像素点,此时再看我们的元素,还是渲染的是750宽度,不仅没有和我们预期的一样撑满屏幕,而且因为在同一尺寸的屏幕上,相较于原来的屏幕,元素反而还在视觉上缩小了。
为此,聪明的浏览器制造商提出了 逻辑像素 这一虚拟值。一块屏幕,除了固定的屏幕像素,还拥有了 逻辑像素 和 设备像素比 这两个属性(对应屏幕分辨率,逻辑分辨率 自然就是一块屏幕的逻辑像素点的个数),它们的关系是:
在任意一块指定的屏幕上,
屏幕分辨率 = 逻辑分辨率 x 设备像素比
等同于:屏幕像素点个数 = 逻辑像素点个数 x 设备像素比
而真实屏幕的尺寸是不变的,所以
单个屏幕像素点尺寸 x 屏幕像素点个数 = 单个逻辑像素点尺寸 x 逻辑像素点个数
根据上面的等式,可以得出:
单个屏幕像素点尺寸 x 设备像素比 = 单个逻辑像素点尺寸
在这种情况下,我们书写元素的逻辑尺寸(基于逻辑像素),就会因为设备像素比的存在,映射为对应的设备像素。
比如,我们在iphone6书写375个逻辑像素宽度的元素,就会因为iphone6的dpr为2,而渲染出一个设备尺寸宽度为750个设备像素点的元素。当这块屏幕的设备分辨率升级,其dpr为3时,就会渲染出1124个屏幕像素点宽度的元素。
问题看似已经完美解决,但是我们还忽略了一种情况,当屏幕的尺寸不同时呢?我们期望书写一个占满屏幕宽度的元素时,我们可能会书写375个逻辑像素的宽度,但若这块屏幕比较特殊,它的设备分辨率为1242x2688,dpr为3,那就以为着要填满这块屏幕的宽度,需要书写414个逻辑像素点,而我们只有375个逻辑像素点,势必不能达到我们的期望。
聪明的开发者,因此又提出了自适应的方案,具体方案是,假设我们以375个屏幕像素点为占满屏幕的标准,我们提出一个新的单位,这个单位根据不同的屏幕逻辑尺寸的不同,其真实尺寸会渲染不同个数的逻辑像素点。比如,在iphone6这个逻辑尺寸为375的屏幕上,它的一个单位就是一个逻辑像素点,而在iphone xsmax这块逻辑尺寸为414屏幕上,其尺寸为414/375个逻辑像素点,那样的话,我们书写同样数量的这种单位(375个),在iphone6上就会得到一个375逻辑像素点的元素,在iphone xsmax上就会得到一个414逻辑像素点的元素。
这个神奇的东西怎么落地呢?答案是rem,rem是浏览器内描述尺寸的一个单位,它直接对应页面根元素的字体大小font-size。
我们只要能够是根元素内字体的跟随屏幕逻辑尺寸变化,并且所有的元素尺寸都使用这个单位,就可以将这种特性表达到我们书写的所有元素尺寸上。
假设我们将html.font-size设置为对应屏幕的逻辑分辨率,比如在375px屏幕上,1rem=375px,在414px屏幕上,1rem就是414px,此时我们已经实现了自适应,我们书写一个在375px屏幕上实际上为375px的元素,就是375x1%375 rem的尺寸,就是1rem,在414px的屏幕上,就是414 * 1 / 414 rem = 1rem。这样是不是很乱,那么我们将html.font-size做一些调整。
var getUnit = function() {
return 100 * (innerWidth) / 375;
};
这里我们将html.font-size设置为在375px屏幕里表达为100px,那么我们写宽度满屏的元素就是3.75rem。这样的话,在414屏幕里,1rem被定义为100x414/375,同样的3.75rem的表达了3.75x100x414/375的尺寸,也就是414px。 至此,我们就实现了书写尺寸的自适应,我们利用 跟随屏幕设置rem这一浏览器支持的单位,抹平了不同逻辑尺寸屏幕的差异,使得一套开发尺寸的屏幕自适应。
业界还有几种不同的方案,本质上大同小异,比如支付宝小程序的rpx,它利用了自身的框架特性,提供了750rpx代表满屏的设计,rpx会跟随不同逻辑尺寸的屏幕进行换算,本质上还是实现了自适应,其设计目的可能是为了更加简单的书写吧,只要设计稿定义为750,照着写rpx就没问题。
还有其他的一些补充: 上面所探讨的都是在移动端内的场景,在这个场景下,势必绕不开一个视口的概念,只是现在一般说到视口就是满屏幕尺寸,且不可缩放。 在移动端浏览器,视口包括布局视口与视觉视口,在不可缩放的情况,它们并没有区别。