09 August 2014

关于移动端自适应页面的一些总结

移动端项目,由于手机屏幕大小不一,基本都需要实现自适应(貌似现在网上流行叫适配)。

目前个人使用的移动端自适应基本上有这么几种办法:

  • 所有定位用百分比 %
  • 所有单位 em
  • 所有单位 rem

将自己最近几个项目踩的坑一个一个列一列,做个总结。

以下的内容都是针对移动端,并未考虑PC端

1. 百分比定位

百分比定位,既整个页面,都使用百分比作为单位,包括marginpaddingwidthheighttopleft等。

这有例子:点击查看百分比布局例子 (由于是移动端项目,推荐使用手机模拟器查看)

如果想要熟练进行百分比布局,首先就要清楚他们各自的百分比是相对于谁来计算的。

首先:marginpaddingwidthleftright这几项的百分比,全部都是按照其父元素宽度的百分比进行计算的。(天坑:安卓2.3中,margin-top是按照高度计算百分比的,后面细说)

然后就是,heighttopbottom的百分比是按照父元素的高度计算的。

发现没有,height 是按照父元素的高度计算的,那该如何实现宽度自适应呢?

在元素宽高比已知的情况下,可以通过设置 padding-top 的百分比为高宽的百分比例,即可将元素按一定比例进行宽度自适应了。

但这样做有个劣势就是如果这个元素内部还有别的元素,需要将内部元素的父元素设置为 position:absolute ,否则内部元素将被padding顶下来。

然后就是布局,全部用 margin 定位。(当然了,如果你某些元素需要高度自适应,需要使用 height 百分比与 top 百分比,自己抉择)

如果有人比较追(qiang)求(po)完(zheng)美(比如我这个强迫症),想让字体大小也自适应缩放,一开始我是这样做的。

设置字体的单位为 em ( or rem ,后细说),然后绑定 window.onresize ,得到屏幕宽度与你的UE图大小的原始宽度的比例,并将 body 上的 font-size 设置等比乘上这个比例即可。

好了,说说上面提到的那个天坑。

测试安卓2.3的时候,我发现了一个很蛋疼的事情,某些安卓2.3中,默认浏览器中的 margin-top 是按照高度 height 的百分比计算的,这样的话,我想实现宽度自适应的垂直位置定位, margin-toptop 属性都是基于高度计算百分比的,无解。

最后我是按照前面设置 font-size 的那个办法,window.onresize 时判断屏幕宽度来设置 top 的比例。两个字—蛋疼。

于是乎,我开始研究新的自适应布局方式,然后某一天我惊讶的发现, emrem 单位,完美被移动端设备支持!!!

2. em布局

em布局,前面提到过 em 单位,如果不清楚em单位的定义可以google or 问度娘,这里不做概念性介绍,只记录用法。

所有距离单位都可以使用 em 作为单位,我发现有些同学以为只有字体可以设置 em(虽然这货本身就是一个描述字体的单位..),其实所有属性的单位都可以使用 em 的, em 是什么呢? font-size 属性上的 em ,是相对其父元素的字体大小的比值。如果等于其父元素字体大小,既 1em

pxem 的关系为:

如果父元素字体为 16px ,那么 1px = 16em 。方便的做法是在 body 上设置 font-size:62.5% ,然后 1em=10px ,或者使用公式 1em =1*1px/16 来设置 em 的值。

其实如果存在子元素与父元素字体大小不一样的情况,都还好,还能忍。。

不能忍的是,一个元素的 widthheightpaddingmargintopleft 等属性的 em 值,是按照元素自己的字体大小计算的!这样的话,如果你的父元素上设置了字体大小,你按比例计算完自己的字体大小后,还得计算每一个 width…等属性的 em 值!四个字–灰常蛋疼!

好了,不能忍,跟原工作室老大吐槽,这个时候他提醒我, rem 啊,caniuse一查,我擦咧,安卓2.3+全部支持,好了,刚拿到手的 em 马上丢掉,转投 rem

Ok,重头戏来了!

3. rem布局

rem是什么?它其实跟 em 灰常接近,只是相对的元素不一样了。

em 是相对父元素,而 rem 指的是相对 root element。什么是root element?就是一个页面DOM tree的根节点,html标签。

那么所有单位都使用 rem 的效果是什么呢?

当我们所有单位都设置成 rem 后,整个页面的大小比例都基于一个值,root element的字体大小!

随便你想怎么适应,只要元素内部宽高比例不变,改变一个字体大小就可以了!

当将html上的font-size从1%~100%变,你可以很爽的看到整个页面像被矢量放大一样变大,试试吧,感觉良好!

有怎么改变字体大小呢?其实前面已经提到过了,想怎么变, window.onresize 时设置比例就哦可了。

具体做法可以参考这里

总结

其实并没有说哪一种布局好,最好的做法其实是把这三种结合起来使用的,只要你清楚明白他们具体的用法,每一种都用的炉火纯青,具体哪些元素用哪个单位,信手拈来,武林高手都是不拘于条条框框的,将他们都理解透,结合起来,这样才是最高境界。

(写的乱七八糟。。欢迎讨论交流拍砖)

2014.11.4日补充

关于计算屏幕宽度并设置html上的rem值的js代码,最开始我是用的自己的粗糙版本,后来代码由介右同学加工优化后,我参考了winter的手机淘宝的解决方案,并结合了自己的使用场景,整理了一版放在了这里

该方案自去年我在组里推广后,已从去年开始投入到生产环境。

2015.5.10日补充

其实光用rem实现了宽度自适应还是没用,当一些需要布满全屏的页面,光宽度自适应了,你还需要面对各种各样高度的情景。

当然media-query是最好使的,但是你不能直接写死高度,我试过,写了5、6套,还是不够用。

由于rem布局的页面整个页面大小已经是相对宽度的了, 其实要实现真正覆盖所有case, 必须高度也使用百分比来写media-query

折腾后发现一个神器 – media-query中的aspect-ratio宽高比!

通过rem布局以及aspect-ratio可以简单粗暴的解决一切分辨率下的移动端页面适配问题,简直是太暴力了!

总结的文章还没写, 有兴趣的同学可以自己先研究一下aspect-ratio,文章出来以后我将及时更新。Thx!

Posted in 2014-08-09 17:20