移动页面适配方案

问题重述

本文讨论的适配不是指传统的@media媒体查询

  • media query用于区分移动设备和PC、Pad,需要针对这些设备写3套样式,一般是百分比宽度+小屏隐藏部分内容

  • 本文讨论的适配是希望在不改变页面布局/内容的前提下,希望页面在各个移动设备上视觉效果大致相同,例如:

    我们希望在iphone6上和iphone4上效果大致相同,单纯css是不行的,需要js配合布局才能适应各种各样的移动设备,适配移动设备屏幕有很多难点:

  • 屏幕宽高比不同

    有很矮很胖的手机,也有很窄很长的手机

  • dpi不同

    有屏幕特别小,但分辨率特别高的屏幕

  • 高清屏幕(retina)下图片失真

    有把一个像素点掰成几瓣显示的屏幕

media query无助于解决这些问题,本文讨论的方案也只能勉强解决(麻烦,或者存在副作用)

一.scale/zoom缩放整个页面

1.scale与zoom的区别

  • zoom缩放,默认以左上角为中心,不能改,不存在覆盖周围元素的问题

  • scale缩放,默认以中心位置为中心,可以改,存在覆盖周围元素的问题(扩展出的东西不占空间)

  • zoom对子元素缩放,会破坏对齐

  • scale对子元素缩放,会破坏对齐,用于inline元素无效

  • zoom对父元素缩放,不会影响相对位置

  • scale对父元素缩放,如果设置以左上角为中心就不会影响相对位置

  • zoom兼容除Firefox之外的任何浏览器(IE5.5+)

  • scale兼容IE11+,兼容Firefox

DEMO: scale和zoom的区别

2.scale的副作用

  1. input光标变粗

    scale对整个页面缩放会导致IOS下页面里的Input和Textarea等输入框的光标变粗,超难看,安卓好像不会

    解决方案:放弃scale适配,改用其他方案

  2. z-index

    scale可能对z-index的效果有影响,不确定,因为z-index, fixed, 软键盘这几个因素会相互影响,引发极难解决的其它问题

    解决方案:float会让z无效,position的默认值也会让z无效,更多信息请查看div层调整zindex属性无效原因分析及解决方法

  3. 水平滚动条

    宽屏下可能出现消不掉的水平滚动条,无论怎么设置overflow都无效

    解决方案:不要给body设置scale,给wrapper设置。如果本来就是这样就反过来做(给body设置scale),还不行就考虑剥离其它因素,z-index, fixed, input等等都可能与这个有关

  4. fixed布局失效

    scale之后fixed布局会失效,fixed部分会跟着页面滚动,软键盘弹出也会引发这个问题

    解决方案:改用absolute + js辅助定位,如果是复杂的fixed布局,比如fixed层上有input,还是放弃scale适配吧,bug会没完没了的

  5. 软键盘破坏布局

    弹出软键盘后fixed布局就失效了,目前没得解

3.结论

可以放心去用scale缩放适配“简单”页面,“简单”的定义是:

  1. 没有input,textarea等输入框,保证不会弹出软键盘

  2. 没有复杂的z-index层级

  3. 没有fixed部分

如果页面不满足上面的任意一条,建议不要用scale来缩放适配,会被bug轰炸的

P.S.zoom缩放适配笔者用的不多,至于用scale还是zoom,有以下原则:

  1. 大前提:移动页面不要求支持IE的话可以用scale,否则乖乖用zoom吧,如果兼容Firefox很重要的话,还得添上hack

  2. 图片缩放用zoom和scale都行,整页缩放建议使用scale

4.案例

高德地图_绿色出行活动:scale缩放整页适配

5.框架

白树的pageResponse,1.4K超轻量

二.fontsize + em/rem相对单位

1.用em缩放

需要给html(或者body)设置font-size: 62.5%;(所谓的65.5%hack,为了让1em=10px方便计算)。然后把所有长度单位统一成em,当然,还需要配合js动态改变html(或者body)的font-size

DEMO: 用em缩放适配(注意:当前元素的fz值会影响top/left/right/bottom定位,所以只能再套一层控制fz,外层用来定位

不建议使用em,因为:

  1. 难算

    当前元素的fz值来自所有祖先元素

  2. 冗余标签

    见上面的注意部分

  3. 不够灵活,难以维护

    当前元素的fz值也会影响所有子元素

2.用rem缩放

最重要的是兼容性:[IE8-]不支持rem

必须html设置font-size: 10px;(10px还是为了好算)。然后所有长度单位统一用rem,再配合js设置html的fz值就好了

DEMO:用rem缩放适配

建议尽量使用rem,rem不存在继承值的问题,无需关注祖先的fz值,非常灵活,唯一缺点是兼容性问题([IE8-]不支持)

3.注意事项

用em/rem要注意Chrome某些版本不支持font-size小于12(即便设置了fz为10,实际渲染效果也是12),62.5%hack会失效,此时1em/1rem就不等于10px了,而是等于12px

在高版本的Chrome中,设置-webkit-text-size-adjust: none;也没有用,移动端效果未知

4.案例

淘宝网移动版:单屏 + js模拟滑动(很强大的哟~)

5.用em/rem的好处

(一点题外话,和本文内容没什么关系)

有的页面只对文本用em/rem做字体单位,其它都用px,这是为什么?

因为px是绝对单位,而用户可以设置浏览器的默认字体大小,此时如果文本的单位是px,文本就不会根据用户的设置放大/缩小,而em/rem会

三.img+div宽度百分比,高度auto

这是老方法,没什么新奇的,缺点是文本不会跟着缩放,有两种解法:

  • 把文本都切在图片里

    缺点是页面加载变慢

  • js手动计算改变fz值缩放字体(配合em/rem)

    根据屏幕宽高、dpi等值计算出特定的比例因子,给基础fz乘上来缩放字体,缺点是费劲,而且很难算出合适的比例因子(只能适配部分机型)

DEMO:不给了,看案例吧

案例

四.移动页面适配方案总结

  1. 首选scale/zoom方案,前提是页面简单(简单的定义见前文)

  2. 不行就考虑rem/em方案,注意兼容性(rem[IE8-])

  3. 实在不行就用img方案,要求不高的话可以不管字体,否则,你悲剧了

参考资料

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

code