移动端适配原理分析

1,346 阅读6分钟

学了移动端适配,写了一些我对移动端适配的思考和推导的过程,如有不对,欢迎指正~

什么是移动端适配?

在不同的移动端屏幕下,页面中的内容都和设计稿一致,都可以按照正常的比例显示,且不失真。


为什么需要进行移动端适配?

以显示一张图片为例,在移动端中,我们可以通过width:100%使图片的宽度适应屏幕的宽度,但高度很难通过百分比设置,如果使用像素px设置,高度则会保持不变,这样就会发生宽度过宽而失真的情况。


如何实现移动端适配?

1. 保证缩放前后的比值为1 : 1

  1. 缩放前的高度/缩放后的高度=缩放前的宽度/缩放后的宽度
  2. 缩放前的宽度/缩放前的高度=缩放后的宽度/缩放后的高度

2. rem单位 --> 让其他元素的高度能够随着html的字体大小而改变

    1. html的字体大小等于1rem --> 例如html的字体大小是20px,1rem=20px
    2. 其他元素的高度根据html的字体大小进行换算 --> 例如1rem=20px,元素的高度=50px,换算成rem=2.5rem

rem开拓了很好的适配方式,使用rem,即使我们使用的是固定比值的rem,但是只要改变html的字体大小,页面的其他高度就会随之改变。例如我们将高度设置为2.5rem,虽然这个2.5的比值是固定的,但只要rem代表的值不同,那么最终的高度就是不同的。

然而屏幕的宽度多种多样,我们不可能使用固定的html字体大小,因此html的字体大小应该使用JavaScript来动态生成。

那么问题来了:html的字体大小应该设置成多少?或者说,应该设置成什么?这里,我们可以通过保证缩放前后的比值为1 : 1的规律来入手。


适配的逻辑推导——html的字体大小应该设置成什么?

在推理之前,需要知道的是,当前屏幕的宽度是可以通过JavaScript来获取到的。具体方法如下:

  1. window.innerWidth
  2. document.documentElement.clientWidth
  3. document.documentElement.getBoundingClientRect().width


接下来是推导过程:

首先使用 a. 缩放前的高度/缩放后的高度=缩放前的宽度/缩放后的宽度 的思路进行推理(后面简写为高高比值和宽宽比值):

这个思路的核心是,使用宽宽比值来代替高高比值。因为屏幕的宽度能够通过js的方法来获取,而高度很难。既然两者比值相同,就没必要计算高度的比值了。

假设:设计稿的宽度是375px,html的字体大小为20px,设计稿的高度设为2.5rem(也就是50px)。改变后,屏幕为750px,也就是原来的两倍。

问题:750px宽的屏幕,html的字体大小是多少?

这里要强调一下,高度依然是2.5rem,这是不变的,但是此时的2.5rem应该代表100px。所以html的字体大小应该变为20px*高高比值。又因为宽宽比值等于高高比值,也就是说改变后的html的字体大小等于宽宽比值*20,根据以上的假设,可以得到宽宽比值=2。html字体大小等于40。

可以得到公式:document.documentElement.style.fontSize(js设置html的字体大小)=window.innerWidth(当前屏幕宽度)/375*20+'px'

注意:这里不一定要使用375,但是不管使用什么值,得到的比值都是相同的,这一点是不会改变的。

直接将html的字体大小设置成375px,那么就可以进一步简化公式,得到:document.documentElement.style.fontSize=window.innerWidth

也就是说,设置html的字体大小等于当前屏幕宽度就OK了,只是页面中高度的设置,要根据375计算出rem的比值,不方便计算。这个很好解决,我们让375/18.75,得到20,就方便计算了。注意:这个18.75是任意的,可以使用任何的值。

最终的公式:document.documentElement.style.fontSize=window.innerWidth/Ratio(任意数值)


使用 b. 缩放前的宽度/缩放前的高度=缩放后的宽度/缩放后的高度 的思路进行推理(后面简写为前宽高比和后宽高比):

假设:设计稿的宽度是375px,html的字体大小为20px,设计稿的高度设为2.5rem(也就是50px)。改变后,屏幕为750px。

问题:750px宽的屏幕,html的字体大小是多少?

一样的题目,不一样的解法~

和之前一样,高度依然是2.5rem,这是不变的,只是此时的2.5rem应该代表100px。将需要求的html字体大小设为fontSize。因为前宽高比等于后宽高比,可以带入公式并计算:

375/2.5*20=750/2.5*fontSize --> 375*2.5*fontSize=2.5*20*750 --> 得到fontSize=40

将window.innerWidth代替750带入公式,可以推导出window.innerWidth和fontSize的关系:

公式运算:375/2.5*20=window.innerWidth/2.5*fontSize  --> 交叉相乘 --> 

375*2.5*fontSize=2.5*20*widow.innerWidth

最终可以得到:fontSize=(20*widow.innerWidth)/ 375

和之前一样,将html的字体大小设置为375,可以简化公式,得到:document.documentElement.style.fontSize=window.innerWidth

同样的,375并不方便计算,除以一个数值方便计算。

最终的公式是一样的:document.documentElement.style.fontSize=window.innerWidth/Ratio(任意数值)


适配单位rem转换工具

在GitHub上搜索cssrem,根据提示进行下载安装,可以自动将px转为rem。

配置参数:px_to_rem - px转rem的单位比例,默认为40。这个参数需要自己根据需求手动设置。例如设计稿是375的,除以18.75后,设计稿html字体大小等于20,那这个就设置成20。

注意:这里20的比例,只是当前的设计稿页面,px转rem的比例是20,其他页面的比例依然是不同的,只是js会进行适配。


适配的具体代码

function setRemUnit(){

    var docuElem=document.documentElement,

    //minWidth和maxWidth用于设置屏幕适配的范围
    minWidth=320,

    maxWidth=840,

    ratio=18.75;

    viewWidth=docuElem.clientWidth || docuElem.getBoundingClientRect().width;

/*设置当屏幕宽度大于最大值或小于最小值时不再适配。
因为viewWidth获取到的是css像素而不是物理像素,因此除以dpr才能得到实际的物理像素进行比较。*/

    if(maxWidth&&(viewWidth/dpr>maxWidth)){

//最终的viewWidth要用物理像素乘以dpr还原回css像素的值

        viewWidth=maxWidth*dpr;

    }else if(minWidth&&(viewWidth/dpr<minWidth)){

        viewWidth=minWidth*dpr;

    }

//设置html的font-size

    docuElem.style.fontSize=(viewWidth/ratio)+'px';

}

setRemUnit();

window.addEventListener('resize',setRemUnit);