众所周知,移动端适配的问题一个长期且艰巨的任务。市面上的适配方案也是五花八门,而且在不断的更新。但是大部分的方案依旧在被使用,那就证明在不同需求下不同的方案是具有其实用性的。那本文将会简单的讨论下笔者尝试过并且运用在生产环境中的几种常见的方案。
直到目前位置,笔者尝试过的移动端的尺寸适配的方案也有好几种,从最初的百分比单位,到rem
,再到vh,vw
,再到结合flex
布局去使用这些适配单位,依旧在不断的去优化跟尝试新的方案,也试着将这几种融合起来去使用。运用到生产环境后,取得了一些小成效,同时也发现了一些小缺点。下面将会分别对这几个方案进行简单的讨论,分享下笔者使用时所遇到的一些问题以及使用场景。
-
百分比单位(
%
)
百分比单位是学习前端的时候最快接触到的一个尺寸单位,%
会基于父元素的尺寸进行分配。如果父元素是一个200px * 400px
的盒子的话,子元素设置width: 80%
,则宽度会设置成160px
,高度的话同理,百分比基于父元素的尺寸去做计算。对于父元素的尺寸的定好的情况,百分比是非常好用的。那么如果父元素没有固定尺寸,是根据子元素的尺寸去撑大的情况呢?那么我们就会发现实际上显示出来的高度是为0
,而宽度不为0
,不设置尺寸的父元素,其宽度会继承其上一级的宽度,而高度则不会,默认为0
。那么我们子元素所设置的百分比,宽度的值是正确的,高度为0
。因为百分比基于父元素的尺寸去计算,父元素宽度不为0
,则可以计算出非零数值,而高度为0
,计算出来只能为0
。因此在父元素没有固定尺寸,需要通过子元素去撑大的情况,高度使用百分比会得到0
。所以高度使用百分比应该谨慎使用。那么如果我们使用百分比去做适配不同尺寸的手机屏幕,保证在所有尺寸的手机屏幕上面都能以正确的比例去复刻UI设计的话,那么我们应该在根元素那里设置好具体尺寸,那样百分比才可以基于这个尺寸一级一级的计算下去。
-
rem
单位
其实我们可以很直观的发现,如果我们的UI需求是可无限加载的滚动列表的话,那么根元素上面就无法设置具体的高度,那么百分比在高度上面就会失效。那么我们只能设置具体高度给列表项,但是这样无法保证列表项在不同尺寸上面所保持的比例跟UI设计是一致。这就是百分比单位适配的一个很明显的缺点。但是如果UI设计上不要求单项比例与UI保持一致的话,那么依旧可以使用百分比单位。
那么,既然百分比单位无法满足我们的需求的话,我们就开始寻找新的方案。这时候很容易就会发现到大家一直在说的rem
单位,rem
也是web支持的众多尺寸单位中的一个,与其很像的是em
,那么em
跟rem
有什么区别呢?em
是基于父元素的font-size
属性,而rem
则是基于根元素的font-size
属性,如果父元素设置了font-size: 50px
,那么子元素的1em == 50px
。而且如果子元素不设置font-size
,会默认继承父元素的font-size
,那么子元素的子元素的同样满足1em == 50px
。那么可以直观的理解得知,要是子元素设置了自己的font-size
,那么就不再满足上面的等式。所以如果当父元素需要设置自己的font-size
,而其子元素有想要基于祖父元素(父元素的父元素)去做em
去设置尺寸的话,就会处于一个尴尬的情况。
那么rem
又有什么不同呢?上面的时候我们提到了rem
是基于根元素的font-size
的大小,如果根元素设置了font-size: 50px
,则我们在其任何子元素中或者嵌套的多级子元素中,使用width: 1rem
,会得到width: 50px
的反馈,而且无视于父元素的font-size
是设置了什么值。即解决了em
单位在上述提及的尴尬情况。但是需要注意的是,因为font-size
是可以逐级继承传递下去的,所以最好在根元素下的第一级元素上将font-size
设置回默认值。之所以这么做的原因是,如果在逐级嵌套的过程中,出现了文本节点,但是却又没有设置对应的font-size
,那么该文本节点的字体大小将会是根元素所设置的font-size
大小,就会出现字体很大的情况。假如大部分文本节点的所需字体大小均为同一尺寸的话,那么在每一个文本节点的地方再重新设置font-size
的值,其实会很不便。所以在根元素下的第一级的子元素设置好font-size
的大小,那所有的文本节点就会继承这个font-size
的值,而不是根元素的。因此就可以不用在每个文本节点处去设置字体大小。
简单的介绍完了em & rem
这两个单位,我们发现em & rem
都有其适合的使用场景,但是相比之下rem
可能更适合于去做整体的适配方案。那么我们应该怎么去确定1rem
的大小呢?在网上的资料中有多种确定的方案,其中主要就是两种核心计算方式。
第一种就是,根据尺寸范围去确定,也就是在移动端中的多种尺寸中,划分出多个范围,在每个范围中确定一个固定的数值。其具体实现就是结合媒体查询,在不同范围内的屏幕尺寸设置一个固定的值,这样去做适配。
另外一种就是,根据屏幕宽度跟设计稿宽度去做计算,得到一个数值。这样计算在所有的尺寸均能得到一个对应的唯一的值。其具体实现则是通过js去获取到当成设备的屏幕宽度然后去跟设计稿的宽度进行转换,计算得出一个值,然后在通过js动态设置到根元素中。
这两种的思路大体就是上述所讲的,然而具体的转换计算则不同公司有不同的想法。具体的转换可以点击这里。笔者自己采用方案是第二种,根据屏幕宽度跟设计稿宽度去转换,那么下面会介绍下笔者是怎么转换的。
笔者的转换计算方式其实与网易手机端的计算方式是一致的,不过想出这个转换计算方式并没有像网易那样理解了那么多,纯粹只是这个样算会很方便而已。因为拿到手的设计稿是750宽度的,一开始试过750px
转成75rem
的,那么实际设备的1rem
大小就是通过使用屏幕宽度去除75
得到1rem(实际设备)
,也就是1rem(实际设备) = w(屏幕宽度)/75
,但是后来试了发现1rem=10px(设计稿)
的这个计算,在chrome
上面会无效,chrome
最小只能到12px
,而实际计算出来的 1rem
远小于12px
的,因为手机的宽度大部分在360
到480
之间,这样子计算出来的1rem(实际设备)
肯定小于12px
的。后来就换成1rem=100px(设计稿)
,也就是750px=7.5rem
。之所有将1rem=10px或者1rem=100px
,纯粹只是因为这样算,在切设计稿的尺寸的时候很方便,如果设计稿是有一个元素要130px * 80px
,那么只需要设置1.3rem * 0.8rem
。在计算上面只需要除100,可以直接在切图的时候就能计算出来,也不需要使用计算器去一个个去算,后来是这套方案使用了好一段时间后,才看到上面链接的那个博客介绍到网易手机端也是这么做的,而且考虑的远比我要想的多得多,才发现原来被我瞎猫碰上死耗子。
这套方案很长一段时间都是我做移动端适配的主选方案,直到我遇到了在ios
的webview
上面发现动态加载网络图片使用rem
的时候,图片显示不出来,排查后发现是通过js接口调用后获得的网络图片加载的时候就无法正确的显示设置好的高度。这是我才开始考虑有没有更好的东西去结合rem
去做得更好。因为之前做微信端的h5的时候,从来没有遇到过使用rem会出现比例错误的情况,在我看来rem
仍然是在大部分界面上都能很好的做到适配的。不过在使用的过程中也发现了一些小问题,因为rem
的单位计算是用屏幕宽度去处于7.5
这个基数,得到的1rem(实际设备)
的值不能保证是整数,所以设计稿上面一些小的间距,比如小于10px的那种,在css中我们会写0.06rem
这种情况,但是因为1rem
本身就不是整数,所以在进行浮点数计算的时候,会出现细微的差距。但是如果间距采用px
去做,那么rem
就会变的不准,尤其是在宽度上面,本身7.5rem
就是一个屏幕宽度,但是加上px
后就能计算出除去px
后剩下的是多少个rem
。
然后开始全面拥抱弹性布局(flex),在使用flex布局后,发现结合flex跟rem可以做的更好。因为如果间距采用px,某些元素采用rem,那么剩下的可以直接flex拉伸铺满,就不用担心除去px后还剩多少个rem的问题。在移动端上面基本上都是兼容了flex这个特性,所以可以直接使用,不过需要加下对应的内核前缀即可。flex的使用很大程度优化了在布局上面的编写。
后面又发现了vw & vh
这一对,vw
其实就是基于window.innerWidth
,vh
就是基于window.innerHeight
。 100vw
就等于屏幕可视范围的宽度,100vh
就等于屏幕可视范围的高度,在移动端的话就是webview
的尺寸。而且发现到vw
就很像将750px=100rem(设计稿)
的这种情况,这种情况下的1rem
的大小就跟1vw
的大小是一致的,所以vw的使用上基本与rem的使用相似。而且一屏的宽度等于100vw也很像百分比,但是vw却是基于屏幕宽度的,而不会想百分比那样基于父元素,所以在横向的适配上做到很不错的效果。但是vh
呢?因为有时候需要做一个H5
界面是要一屏的宽高,这时候vh
就发挥出它的作用了,正常情况,100vh
就是一屏的高度。但是在使用vh的过程遇到过一个问题,就像一个一屏的H5注册页,里面有input
标签,需要用户填入信息。将背景图的高度设置为100vh
,当输入框聚焦后,手机键盘弹起,这时候背景图就会被压缩,因为手机键盘弹起后,屏幕的可视高度就是一屏的高度减去手机键盘的高度,因此100vh
就会变成这个高度而不再是一屏的高度。这个问题就是使用vw跟vh
的时候遇到过的唯一问题。暂时还没想出好的解决方法。如果不会出现键盘弹出的情况且又需要一屏的高度的时候,很推荐使用vh
。而vw
则暂时还没遇到过问题。
总结
适配方面尝试过好几种方法,每种方法都有其优点跟缺点,但是根据使用场景去选择跟结合来使用,就可以做到相当不错的适配效果了。
注:后续会添加一些代码图片跟实际效果的图片