viewport
之前写的几篇移动端的知识,然后经过导师的分享,看了荔枝fm的适配,发现自己对viewport的理解并不是很深,于是花了一两天的时间研究viewport和荔枝fm的适配方案。
首先viewport的深入理解,移动前端开发之viewport的深入理解 这篇文章真的讲得很好,很细致
本文文字比较多,因为理论知识比较多,所以希望能够看完,因为本文是参考上面博客和慕课网和各种百度理解之后的总结,看上面博客不理解的东西也在理解之后一并写了出来。
首先我们先想一个问题,一个宽度1000px的页面在一个逻辑像素320px的手机端上面是怎么显示的?
首先我们从小学初中时候说起,记得以前都是诺基亚手机,一个诺基亚手机已经很厉害了,博主那时候还没有手机,经常拿老妈的手机刷网页版的qq空间和玩一个叫纵横四海的游戏,那时候手机根本不能完全显示整个网页,只能显示一小部分,通过按钮上下左右移动位置拖动网页,这样体验很不好,于是,浏览器那边就提出了一个虚拟的viewport概念,iOS的viewport一般设置成980px而Android就比较多,通过这个viewport,移动端的浏览器就可以把整个网页显示在手机屏幕上,整个网页是被缩小的,字体非常难看,需要放大,我们学校的教务系统用手机访问就是这样,需要放大才能填写登录信息。所以,有了viewport之后,移动web设备上是完全显示一个1000px的页面的。
这里移动端浏览器干了两件事:
- 把整个页面在980px的viewport是渲染出来,这里我们一般称之为layout viewport
为什么需要这个980px的layout viewport来渲染页面呢,试想一下,如果我们把一个1000px的页面渲染在320px的手机端浏览器上,那么,排版就会发生错乱,会有问题,所以才需要一个980px的viewport渲染达到正确排版。
- 通过缩放,把整个页面缩小以至于浏览器能够完全显示整个网页。
然而,layout viewport 的宽度是大于浏览器可视区域的宽度的,所以我们还需要一个viewport来代表 浏览器可视区域的大小,ppk把这个viewport叫做 visual viewport(度量viewport/视口viewport)。visual viewport的宽度可以通过window.innerWidth 来获取,但在Android 2, Oprea Mini 和 UC 8中无法正确获取。
我们可以这样理解,把手机分为两层,底层为layout viewport,手机浏览器把页面渲染在这个viewport上,顶层为visual viewport, 我们可以通过缩放控制显示多大的视口。
不管你是用PC端还是移动端的浏览器去访问一个页面的时候。你所看到的浏览器的窗口就是你visual viewport(通过window.innerWidth/height获取),对于移动端来说,就是你通过浏览器所看到的那部分大小,它的度量单位是px(css中的像素)。这个visual viewport通常是可以变化的,例如你对屏幕进行缩放,这样就可以改变visual viewport的大小,或者你移动屏幕的滚轮,这样就可以改变visual viewport的位置。
而layout viewport,它就相当于一个大的box,所有的内容都要在这个box里面显示。你通过visual viewport所看到的内容就是layout viewport上的部分内容。
把layout viewport想像成为一张不会变更大小或者形状的大图。现在想像你有一个小一些的框架,你通过它来看这张大图。(译者:可以理解为「管中窥豹」)这个小框架的周围被不透明的材料所环绕,这掩盖了你所有的视线,只留这张大图的一部分给你。你通过这个框架所能看到的大图的部分就是visual viewport。当你保持框架(缩小)来看整个图片的时候,你可以不用管大图,或者你可以靠近一些(放大)只看局部。你也可以改变框架的方向,但是大图(layout viewport)的大小和形状永远不会变。
当你进行页面缩放的时,你可以想象你拿着这个小框架离这张大图越来越近了,那么你所看到的大图的内容也越来越少了。原本在未缩放的页面上看起来很小的尺寸,现在通过viewport看上去变大了,事实上这部分的css的px值并没有变化,仅仅是因为进行放大后,css的1px的值所占的屏幕分辨率的值变大了。
同理,当你缩小整个页面的时候,看到大图的内容也越来越多,同时,原本看起来很大的尺寸,现在再通过viewport看上去的时候又变小了。同理,css的1px的值并没有发生变化,但是1px值所占的屏幕分辨率的值变小了。
在放大和缩小的过程中,visual viewport和layout viewport的宽,高都没发生任何的变化,变化的仅仅就像是用户拿着这个visual viewport去远离或者靠近layout viewport,在远离或者靠近的过程中,就会呈现出缩放的效果来。
那么,设计移动web,为什么不使用默认的980px的viewport?
1. 宽度不可控制,不同系统不同设备的默认值可能不同
2. 页面缩小版显示,交互不友好
3. 链接不可点
4. 有缩放,缩放后又有滚动
所以,必须还要有一个能完美适配移动设备的viewport。所谓的完美适配指的是,首先不需要用户缩放和横向滚动条就能正常的查看网站的所有内容;第二,显示的文字的大小是合适,比如一段14px大小的文字,不会因为在一个高密度像素的屏幕里显示得太小而无法看清,理想的情况是这段14px的文字无论是在何种密度屏幕,何种分辨率下,显示出来的大小都是差不多的。当然,不只是文字,其他元素像图片什么的也是这个道理。ppk把这个viewport叫做 ideal viewport,也就是第三个viewport——移动设备的理想viewport。
ideal viewport并没有一个固定的尺寸,不同的设备拥有有不同的ideal viewport。所有的iPhone的ideal viewport宽度都是320px,无论它的屏幕宽度是320还是640,也就是说,在iphone中,css中的320px就代表iphone屏幕的宽度。但是安卓设备就比较复杂了,有320px的,有360px的,有384px的等等,关于不同的设备ideal viewport的宽度都为多少,可以到http://viewportsizes.com去查看一下,里面收集了众多设备的理想宽户。ideal viewport 的意义在于,无论在何种分辨率的屏幕下,那些针对ideal viewport 而设计的网站,不需要用户手动缩放,也不需要出现横向滚动条,都可以完美的呈现给用户。
利用meta标签来设置我们的viewport成为ideal viewport
既然移动端浏览器的viewport默认是layout viewport为980px(大多数),那么我们怎么修改得到ideal viewport呢,这里我们通过meta标签设置(因为现在移动端有专门的设计稿,所以可以把layout viewport设置成ideal viewport而不用担心排版被破坏)
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
在苹果的规范中,meta viewport 有6个属性(暂且把content中的那些东西称为一个个属性和值),如下:
width 设置layout viewport 的宽度,为一个正整数,或字符串”width-device”
initial-scale 设置页面的初始缩放值,为一个数字,可以带小数
minimum-scale 允许用户的最小缩放值,为一个数字,可以带小数
maximum-scale 允许用户的最大缩放值,为一个数字,可以带小数
height 设置layout viewport 的高度,这个属性对我们并不重要,很少使用
user-scalable 是否允许用户进行缩放,值为”no”或”yes”, no 代表不允许,yes代表允许
这些属性可以同时使用,也可以单独使用或混合使用,多个属性同时使用时用逗号隔开就行了。
此外,在安卓中还支持 target-densitydpi 这个私有属性,它表示目标设备的密度等级,作用是决定css中的1px代表多少物理像素
target-densitydpi 值可以为一个数值或 high-dpi 、 medium-dpi、 low-dpi、 device-dpi 这几个字符串中的一个
特别说明的是,当 target-densitydpi=device-dpi 时, css中的1px会等于物理像素中的1px。
因为这个属性只有安卓支持,并且安卓已经决定要废弃target-densitydpi 这个属性
关于同时设置width和initial-scale的问题
有时候我们直接设置<meta name="viewport" content="initial-scale=1">
也可以把当前的的viewport变为 ideal viewport。因为上面的博客有提到缩放是相对ideal viewport来缩放的,所以可以把当前的viewport(layout viewport)设置为ideal viewport的宽度。看了上面那个博客的同学,是不是感到疑惑,那里有一个公式是这样的:
visual viewport宽度 = ideal viewport宽度 / 当前缩放值
当前缩放值 = ideal viewport宽度 / visual viewport宽度
那到底initial-scale缩放的是layout viewport还是visual viewport呢,这里我做了几个测试,结果如下:
1、只设置initial-scale,不设置width
<meta name="viewport" content="initial-scale=2.0">
可以看到iphone6和iphone6 plus下layout viewport和visual viewport都改变了
2、同时设置width和initial-scale
情况一:<meta name="viewport" content="width=device-width initial-scale=0.5">
情况2:<meta name="viewport" content="width=device-width initial-scale=2">
情况3:<meta name="viewport" content="width=800 initial-scale=2">
由上述几种情况,和上面博客谈到的一些知识,可以知道,initial-scale缩放的实际上是visual viewport的值,而width设置的layout viewport的值,两者如果同时设置,layout viewport会取visual viewport和width的最大值,而单独设置一个,就取那个值,layout viewport的值和visual viewport有一定的关系,所以通过单独设置initial-scale是可以将layout viewport的值设置成ideal viewport
由上面的图,我们可以得到这样一个公式:
visual viewport宽度 = ideal viewport宽度 / 当前缩放值
当前缩放值 = ideal viewport宽度 / visual viewport宽度
缩放是相对于ideal viewport来缩放的,缩放值越大,当前viewport的宽度就会越小,反之亦然。例如在iphone中,ideal viewport的宽度是320px,如果我们设置 initial-scale=2 ,此时viewport的宽度会变为只有160px了,这也好理解,放大了一倍嘛,就是原来1px的东西变成2px了,但是1px变为2px并不是把原来的320px变为640px了,而是在实际宽度不变的情况下,1px变得跟原来的2px的长度一样了,所以放大2倍后原来需要320px才能填满的宽度现在只需要160px就做到了。
终于写完了,欢迎有不同见解的小伙伴进行评论,大家共同学习学习