-
-
Notifications
You must be signed in to change notification settings - Fork 94
Description
注: 这篇文章部分内容已经过时,vw 方案(见文末)已经足以适应各种场合,且兼容性很好。
上一篇介绍了像素和视口这些基本概念,现在接着移动端的适配方案。
推荐一篇文章:MobileWeb适配总结,里面说到的三种布局方法已经说的很详细,还分别做了demo,我就不做了,这里说说三种方案的原理以及我使用中的感受,希望各为互补,大家理解是最重要的。
之前做过PC页面的人聊的最多的就是『兼容』,这是因为浏览器之间的差异引起的,不再多说。而移动端是基本没有『兼容』的问题的,全是CSS3,简直不要太开心。可是『适配』问题随之而来。
什么是『适配』?做PC页面的时候,我们按照设计图的尺寸来就好,这个侧边栏200px,那个按钮50px的。可是,当我们开始做移动端页面的时候,设计师给了一份宽度为640px的设计图。那么,我们把这份设计图实现在各个手机上的过程就是『适配』。
那么,我们怎么开始呢?目前有三种方法:
- 固定高度,宽度自适应
- 固定宽度,viewport缩放
- rem做宽度,viewport缩放
这三种方法的核心都是视口的确定,现在以实现这个设计图为例说明。
固定高度,宽度自适应
这也是目前使用最多的方法,垂直方向用定值,水平方向用百分比、定值、flex都行。腾讯、京东、百度、天猫、亚马逊的首页都是使用的这种方法。
随着屏幕宽度变化,页面也会跟着变化,效果就和PC页面的流体布局差不多,在哪个宽度需要调整的时候使用响应式布局调调就行(比如网易新闻),这样就实现了『适配』。
原理
这种方法使用了完美视口:
<meta name="viewport" content="width=device-width,initial-scale=1">
这样设置之后,我们就可以不用管手机屏幕的尺寸进行开发了。
固定宽度,viewport缩放
设计图、页面宽度、viewport width使用一个宽度,浏览器帮我们完成缩放。单位使用px即可。
目前已知荔枝FM、网易新闻在使用这种方法。有兴趣的同学可以看看是怎么做的。
原理
这种方法需要根据屏幕宽度来动态生成viewport
,生成的 viewport 基本是这样:
<meta name="viewport" content="width=640,initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no">
640 是我们根据设计图定下的,0.5 是根据屏幕宽度动态生成的。
生成的viewport告诉浏览器网页的布局视口使用 640px,然后把页面缩放成50%,这是绝对的等比例缩放。图片、文字等等所有元素都被缩放在手机屏幕中。
这个gif图说明了一切:
rem做宽度,viewport缩放
这也是淘宝使用的方案,根据屏幕宽度设定 rem
值,需要适配的元素都使用 rem
为单位,不需要适配的元素还是使用 px
为单位。
具体使用方法见使用Flexible实现手淘H5页面的终端适配
上文提供了sass和postcss的px2rem转换方法,我这里给出less的px2rem
。因为less不支持函数,所以需要安装插件 less-plugin-functions
,然后就简单了:
.function{
.px2rem(@px,@base:72px){
return: @px / @base * 1rem;
}
}
这样使用:
div{
width: px2rem(100px);
}
使用这个方法的库:
原理
实际上做了这几件事情:
- 动态生成 viewport
- 屏幕宽度设置
rem
的大小,即给<html>
设置font-size
- 根据设备像素比(window.devicePixelRatio)给
<html>
设置data-dpr
这么设置的好处是可以让不同设备的rem
或px
都显示一样的长度。
设置rem
设置rem的意义在于得到一个与屏幕宽度相关的单位,本来vw
是最合适的,但是因为兼容性的问题,只能使用rem
来做。这样,让不同设备的rem
显示一样的长度。
vw是CSS3引入的单位,1vw = 1%窗口宽度
上面的布局我们可以这样:
html{
font-size: 屏幕宽度 / 10;
}
.btn{
width:8.75rem;
height:1.25rem;
}
这样,无论屏幕宽度是多少,.btn
都是相对于屏幕的这么宽,做到了适配。
设置 viewport 缩放 和 data-dpr
这两个设置其实是干的一件事,就是适配高密度屏幕手机的px
单位。
.a{
font-size:12px;
}
[data-dpr="2"] .a{
font-size: 24px;
}
[data-dpr="3"] .a{
font-size: 36px;
}
而缩放是动态的,这样,不同设备下的px
显示一样的长度。
之前说过CSS像素和物理像素与缩放、dpr都有关系,这里说明:
在普通手机上,
.a
字体设置为12px;在dpr是2的手机上,
[data-dpr="2"] .a
字体为24px,又因为页面缩放50%,字体为还是12px
总结
坦白说,我不觉得第一种方案能就称为『适配』方案,因为太笨了,只能做一些列表等简单排列的样式。
但是一些复杂的活动页的布局,用它可能就力不从心了:
这是我曾经做过的一个页面,『PK』要和左右两张图平行,而且下面的『不怒自威』、『义薄云天』和下面的战斗力位置都要固定,不能有差。如果用第一种方案,可能各个元素就要绝对定位,然后各种百分比来定位了。且不说计算麻烦,而且辛苦一番最后的结果尺寸是和设计图有出入的。
但是,第二种和第三种方案就绝对不会有这种情况,不会和设计图有差。再说第二种和第三种方案的区别,目前我唯一知道的区别就是第三种方案更加灵活,有两种单位可以使用,想让元素适配的时候就用rem
,想让文字不缩放的时候就用px
。
如果你没有明白我以上讲的,可能是我太啰嗦了,你可以看看下面的那些文章。当然,最好的理解方式就是用这些方案做几个页面,到时候就明白了。
其他文章
- 移动端高清、多屏适配方案
- 从网易与淘宝的font-size思考前端设计稿与工作流
- 百度方案
- 移动端自适应方案 介绍了 flex 布局和rem方案
这两篇文章看着简单,尤其是上一篇讲视口,花费了将近一周的时间去翻阅资料。本来以为很简单的东西,才发现有那么多名堂。好了,后天年会,祝我中大奖吧。
PPT
20170821 update
vw方案: https://www.w3cplus.com/css/vw-for-layout.html
demo: http://huodong.m.taobao.com/act/layouttestvw.html
只要明白 CSS 的 vw
单位是什么意思就明白这个方案了,可以看作是第三种方案的完美版,先定死 viewport,再通过 vw 取代 rem。
Activity
think2011 commentedon Jan 25, 2016
写的很好,很有用,谢谢~
发现一处似乎有问题的句子。
riskers commentedon Jan 26, 2016
@think2011 已修改,谢谢
kisnows commentedon Jan 27, 2016
发现第二个方法好方便,只要计算一下viewpoint就可以了,我以后就用这个方法了
banama commentedon Jan 30, 2016
写的很不错,以前常用第一第三种,今天第一次看到第二种,耳目一新啊,学习了。
kisnows commentedon Feb 1, 2016
发现第二个方法还是有坑啊,比如你很难实现一个整页的 fullpage 应用。
因为当页面大小不同时,scale 是按照屏幕宽度计算的,这样在只要宽高比不同的设备下不借助 js 还真是难以实现。
riskers commentedon Feb 1, 2016
@kisnows 你说的整屏应用我其实一直在思考,似乎没什么好的办法,因为一旦整屏,屏幕中的元素为了保持设计图的比例就要像
background-size
的cover
/contain
一样,必然在屏幕中有『黑边』。上面的三种方法都是在与屏幕宽度有关系,整屏页面是与宽高比有关系,其实挺复杂的。而且这种页面也不适合复杂设计,最好就是每个元素绝对定位来做比较好。
可以参考 #15
SASUKE40 commentedon Feb 1, 2016
@kisnows fullpage應用不建議用這種方式
@riskers 其實荔枝FM的很多頁面都是使用第二種,因為這樣跟設計師非常好交流。另外推薦PPT很贊,末尾還有切圖工具推薦。其實那幾個切圖工具我現在基本不用了,推薦使用Photoshop自帶的【文件-生成-图像资源】切圖,再配合Renamy就非常幸福了~
riskers commentedon Feb 1, 2016
@SASUKE40
那个应该是PS CC 的功能吧,我现在还是CS6,因为懒并不想升级。
荔枝FM的办法的确不错,不过之前使用你们的兼容办法在有些手机的webview中有问题。还没有研究是什么造成的,你们的办法在安卓4.3的手机默认浏览器中都正常么?之前测试拿来一个魅蓝的手机在默认浏览器中就有问题。
leozdgao commentedon Feb 1, 2016
@SASUKE40 @riskers
看了下荔枝FM的首页,发现它并没有做 viewport 缩放,只是固定了布局视口的大小,和第二种方式的描述似乎不太一样。在 chrome 的模拟器中还出现了 font boosting 的现象。
我的理解是:
dpr=1
来处理(也就是initial-scale=1.0
),因为用了根元素字体是根据布局视口大小动态设置的,使用了 rem 作单位的元素总能适配。另外最近遇到单页面适配的问题,感觉 #15 讲的很有帮助:smile: 。
riskers commentedon Feb 1, 2016
@leozdgao
荔枝FM是第二种方法,不过它做了兼容(你的模拟器应该是用的iOS吧):
为什么这么兼容我不太清楚(无非也就是安卓的各个版本、iOS对viewport的支持不同吧),具体要问问 @SASUKE40 了。你可以看看网易那个页面,也做了兼容,不过方法复杂的多。
第三种方法相当于有两种单位让你使用,是比第二种灵活。
leozdgao commentedon Feb 1, 2016
@riskers
额... 🤔 #15 在我的场景,用 contain 模式还是比较适合的。
另外在模拟器上有 Font Boosting,在真机上打开又是正常的,很奇怪。
50 remaining items