viewport

移动前端开发之viewport的深刻理解

在移动设备上进行网页的重构或开发,首先得搞明白的就是移动设备上的viewport了,只有明白了viewport的概念以及弄清楚了跟viewport有关的meta标签的使用,才能更好地让咱们的网页适配或响应各类不一样分辨率的移动设备。javascript

1、viewport的概念css

通俗的讲,移动设备上的viewport就是设备的屏幕上能用来显示咱们的网页的那一块区域,在具体一点,就是浏览器上(也多是一个app中的webview)用来显示网页的那部分区域,但viewport又不局限于浏览器可视区域的大小,它可能比浏览器的可视区域要大,也可能比浏览器的可视区域要小。在默认状况下,通常来说,移动设备上的viewport都是要大于浏览器可视区域的,这是由于考虑到移动设备的分辨率相对于桌面电脑来讲都比较小,因此为了能在移动设备上正常显示那些传统的为桌面浏览器设计的网站,移动设备上的浏览器都会把本身默认的viewport设为980px或1024px(也多是其它值,这个是由设备本身决定的),但带来的后果就是浏览器会出现横向滚动条,由于浏览器可视区域的宽度是比这个默认的viewport的宽度要小的。下图列出了一些设备上浏览器的默认viewport的宽度。html

1

 

2、css中的1px并不等于设备的1px前端

    在css中咱们通常使用px做为单位,在桌面浏览器中css的1个像素每每都是对应着电脑屏幕的1个物理像素,这可能会形成咱们的一个错觉,那就是css中的像素就是设备的物理像素。但实际状况却并不是如此,css中的像素只是一个抽象的单位,在不一样的设备或不一样的环境中,css中的1px所表明的设备物理像素是不一样的。在为桌面浏览器设计的网页中,咱们无需对这个津津计较,但在移动设备上,必须弄明白这点。在早先的移动设备中,屏幕像素密度都比较低,如iphone3,它的分辨率为320x480,在iphone3上,一个css像素确实是等于一个屏幕物理像素的。后来随着技术的发展,移动设备的屏幕像素密度愈来愈高,从iphone4开始,苹果公司便推出了所谓的Retina屏,分辨率提升了一倍,变成640x960,但屏幕尺寸却没变化,这就意味着一样大小的屏幕上,像素却多了一倍,这时,一个css像素是等于两个物理像素的。其余品牌的移动设备也是这个道理。例如安卓设备根据屏幕像素密度可分为ldpi、mdpi、hdpi、xhdpi等不一样的等级,分辨率也是五花八门,安卓设备上的一个css像素至关于多少个屏幕物理像素,也因设备的不一样而不一样,没有一个定论。java

    还有一个因素也会引发css中px的变化,那就是用户缩放。例如,当用户把页面放大一倍,那么css中1px所表明的物理像素也会增长一倍;反之把页面缩小一倍,css中1px所表明的物理像素也会减小一倍。关于这点,在文章后面的部分还会讲到。web

    在移动端浏览器中以及某些桌面浏览器中,window对象有一个devicePixelRatio属性,它的官方的定义为:设备物理像素和设备独立像素的比例,也就是 devicePixelRatio = 物理像素 / 独立像素。css中的px就能够看作是设备的独立像素,因此经过devicePixelRatio,咱们能够知道该设备上一个css像素表明多少个物理像素。例如,在Retina屏的iphone上,devicePixelRatio的值为2,也就是说1个css像素至关于2个物理像素。可是要注意的是,devicePixelRatio在不一样的浏览器中还存在些许的兼容性问题,因此咱们如今还并不能彻底信赖这个东西,具体的状况能够看下这篇文章windows

devicePixelRatio的测试结果:浏览器

14

 

3、PPK的关于三个viewport的理论app

    ppk大神对于移动设备上的viewport有着很是多的研究(第一篇第二篇第三篇),有兴趣的同窗能够去看一下,本文中有不少数据和观点也是出自那里。ppk认为,移动设备上有三个viewport。iphone

    首先,移动设备上的浏览器认为本身必须能让全部的网站都正常显示,即便是那些不是为移动设备设计的网站。但若是以浏览器的可视区域做为viewport的话,由于移动设备的屏幕都不是很宽,因此那些为桌面浏览器设计的网站放到移动设备上显示时,必然会由于移动设备的viewport太窄,而挤做一团,甚至布局什么的都会乱掉。也许有人会问,如今不是有不少手机分辨率都很是大吗,好比768x1024,或者1080x1920这样,那这样的手机用来显示为桌面浏览器设计的网站是没问题的吧?前面咱们已经说了,css中的1px并非表明屏幕上的1px,你分辨率越大,css中1px表明的物理像素就会越多,devicePixelRatio的值也越大,这很好理解,由于你分辨率增大了,但屏幕尺寸并无变大多少,必须让css中的1px表明更多的物理像素,才能让1px的东西在屏幕上的大小与那些低分辨率的设备差很少,否则就会由于过小而看不清。因此在1080x1920这样的设备上,在默认状况下,也许你只要把一个div的宽度设为300多px(视devicePixelRatio的值而定),就是满屏的宽度了。回到正题上来,若是把移动设备上浏览器的可视区域设为viewport的话,某些网站就会由于viewport太窄而显示错乱,因此这些浏览器就决定默认状况下把viewport设为一个较宽的值,好比980px,这样的话即便是那些为桌面设计的网站也能在移动浏览器上正常显示了。ppk把这个浏览器默认的viewport叫作 layout viewport这个layout viewport的宽度能够经过 document.documentElement.clientWidth 来获取。

    然而,layout viewport 的宽度是大于浏览器可视区域的宽度的,因此咱们还须要一个viewport来表明 浏览器可视区域的大小,ppk把这个viewport叫作 visual viewport。visual viewport的宽度能够经过window.innerWidth 来获取,但在Android 2, Oprea mini 和 UC 8中没法正确获取。

2      3

    如今咱们已经有两个viewport了:layout viewportvisual viewport。但浏览器以为还不够,由于如今愈来愈多的网站都会为移动设备进行单独的设计,因此必须还要有一个能完美适配移动设备的viewport。所谓的完美适配指的是,首先不须要用户缩放和横向滚动条就能正常的查看网站的全部内容;第二,显示的文字的大小是合适,好比一段14px大小的文字,不会由于在一个高密度像素的屏幕里显示得过小而没法看清,理想的状况是这段14px的文字不管是在何种密度屏幕,何种分辨率下,显示出来的大小都是差很少的。固然,不仅是文字,其余元素像图片什么的也是这个道理。ppk把这个viewport叫作 ideal viewport,也就是第三个viewport——移动设备的理想viewport。

    ideal viewport并无一个固定的尺寸,不一样的设备拥有有不一样的ideal viewport。全部的iphone的ideal viewport宽度都是320px,不管它的屏幕宽度是320仍是640,也就是说,在iphone中,css中的320px就表明iphone屏幕的宽度。

4          5

可是安卓设备就比较复杂了,有320px的,有360px的,有384px的等等,关于不一样的设备ideal viewport的宽度都为多少,能够到http://viewportsizes.com去查看一下,里面收集了众多设备的理想宽度。

    再总结一下:ppk把移动设备上的viewport分为layout viewport  、 visual viewport   ideal viewport  三类,其中的ideal viewport是最适合移动设备的viewport,ideal viewport的宽度等于移动设备的屏幕宽度,只要在css中把某一元素的宽度设为ideal viewport的宽度(单位用px),那么这个元素的宽度就是设备屏幕的宽度了,也就是宽度为100%的效果。ideal viewport 的意义在于,不管在何种分辨率的屏幕下,那些针对ideal viewport 而设计的网站,不须要用户手动缩放,也不须要出现横向滚动条,均可以完美的呈现给用户。

 

4、利用meta标签对viewport进行控制

    移动设备默认的viewport是layout viewport,也就是那个比屏幕要宽的viewport,但在进行移动设备网站的开发时,咱们须要的是ideal viewport。那么怎么才能获得ideal viewport呢?这就该轮到meta标签出场了。

咱们在开发移动设备的网站时,最多见的的一个动做就是把下面这个东西复制到咱们的head标签中:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">

该meta标签的做用是让当前viewport的宽度等于设备的宽度,同时不容许用户手动缩放。也许允不容许用户缩放不一样的网站有不一样的要求,但让viewport的宽度等于设备的宽度,这个应该是你们都想要的效果,若是你不这样的设定的话,那就会使用那个比屏幕宽的默认viewport,也就是说会出现横向滚动条。

这个name为viewport的meta标签到底有哪些东西呢,又都有什么做用呢?

meta viewport 标签首先是由苹果公司在其safari浏览器中引入的,目的就是解决移动设备的viewport问题。后来安卓以及各大浏览器厂商也都纷纷效仿,引入对meta viewport的支持,事实也证实这个东西仍是很是有用的。

在苹果的规范中,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  这个属性了,因此这个属性咱们要避免进行使用  。

 

5、把当前的viewport宽度设置为 ideal viewport 的宽度

要获得ideal viewport就必须把默认的layout viewport的宽度设为移动设备的屏幕宽度。由于meta viewport中的width能控制layout viewport的宽度,因此咱们只须要把width设为width-device这个特殊的值就好了。

<meta name="viewport" content="width=device-width">

下图是这句代码在各大移动端浏览器上的测试结果:

6

能够看到经过width=device-width,全部浏览器都能把当前的viewport宽度变成ideal viewport的宽度,但要注意的是,在iphone和ipad上,不管是竖屏仍是横屏,宽度都是竖屏时ideal viewport的宽度。

这样的写法看起来谁都会作,没吃过猪肉,谁还没见过猪跑啊~,确实,咱们在开发移动设备上的网页时,无论你明不明白什么是viewport,可能你只须要这么一句代码就够了。

但是你确定不知道

<meta name="viewport" content="initial-scale=1">

这句代码也能达到和前一句代码同样的效果,也能够把当前的的viewport变为 ideal viewport。

呵呵,傻眼了吧,由于从理论上来说,这句代码的做用只是不对当前的页面进行缩放,也就是页面本该是多大就是多大。那为何会有 width=device-width 的效果呢?

要想清楚这件事情,首先你得弄明白这个缩放是相对于什么来缩放的,由于这里的缩放值是1,也就是没缩放,但却达到了 ideal viewport 的效果,因此,那答案就只有一个了,缩放是相对于 ideal viewport来进行缩放的,当对ideal viewport进行100%的缩放,也就是缩放值为1的时候,不就获得了 ideal viewport吗?事实证实,的确是这样的。下图是各大移动端的浏览器当设置了<meta name="viewport" content="initial-scale=1"> 后是否能把当前的viewport宽度变成 ideal viewport 的宽度的测试结果。

7

测试结果代表 initial-scale=1 也能把当前的viewport宽度变成 ideal viewport 的宽度,但此次轮到了windows phone 上的IE 不管是竖屏仍是横屏都把宽度设为竖屏时ideal viewport的宽度。但这点小瑕疵已经可有可无了。

但若是width 和 initial-scale=1同时出现,而且还出现了冲突呢?好比:

<meta name="viewport" content="width=400, initial-scale=1">

width=400表示把当前viewport的宽度设为400px,initial-scale=1则表示把当前viewport的宽度设为ideal viewport的宽度,那么浏览器到底该服从哪一个命令呢?是书写顺序在后面的那个吗?不是。当遇到这种状况时,浏览器会取它们两个中较大的那个值。例如,当width=400,ideal viewport的宽度为320时,取的是400;当width=400, ideal viewport的宽度为480时,取的是ideal viewport的宽度。(ps:在uc9浏览器中,当initial-scale=1时,不管width属性的值为多少,此时viewport的宽度永远都是ideal viewport的宽度)

最后,总结一下,要把当前的viewport宽度设为ideal viewport的宽度,既能够设置 width=device-width,也能够设置 initial-scale=1,但这二者各有一个小缺陷,就是iphone、ipad以及IE 会横竖屏不分,统统以竖屏的ideal viewport宽度为准。因此,最完美的写法应该是,二者都写上去,这样就 initial-scale=1 解决了 iphone、ipad的毛病,width=device-width则解决了IE的毛病:

<meta name="viewport" content="width=device-width, initial-scale=1">

 

6、关于meta viewport的更多知识

一、关于缩放以及initial-scale的默认值

    首先咱们先来讨论一下缩放的问题,前面已经提到过,缩放是相对于ideal viewport来缩放的,缩放值越大,当前viewport的宽度就会越小,反之亦然。例如在iphone中,ideal viewport的宽度是320px,若是咱们设置 initial-scale=2 ,此时viewport的宽度会变为只有160px了,这也好理解,放大了一倍嘛,就是原来1px的东西变成2px了,可是1px变为2px并非把原来的320px变为640px了,而是在实际宽度不变的状况下,1px变得跟原来的2px的长度同样了,因此放大2倍后原来须要320px才能填满的宽度如今只须要160px就作到了。所以,咱们能够得出一个公式:

visual viewport宽度 = ideal viewport宽度  / 当前缩放值

当前缩放值 = ideal viewport宽度  / visual viewport宽度

    ps: visual viewport的宽度指的是浏览器可视区域的宽度。

    大多数浏览器都符合这个理论,可是安卓上的原生浏览器以及IE有些问题。安卓自带的webkit浏览器只有在 initial-scale = 1 以及没有设置width属性时才是表现正常的,也就至关于这理论在它身上基本没用;而IE则根本不甩initial-scale这个属性,不管你给他设置什么,initial-scale表现出来的效果永远是1。

    好了,如今再来讲下initial-scale的默认值问题,就是不写这个属性的时候,它的默认值会是多少呢?很显然不会是1,由于当 initial-scale = 1 时,当前的layout viewport宽度会被设为 ideal viewport的宽度,但前面说了,各浏览器默认的 layout viewport宽度通常都是980啊,1024啊,800啊等等这些个值,没有一开始就是 ideal viewport的宽度的,因此 initial-scale的默认值确定不是1。安卓设备上的initial-scale默认值好像没有方法可以获得,或者就是干脆它就没有默认值,必定要你显示的写出来这个东西才会起做用,咱们无论它了,这里咱们重点说一下iphone和ipad上的initial-scale默认值。

   根据测试,咱们能够在iphone和ipad上获得一个结论,就是不管你给layout viewpor设置的宽度是多少,而又没有指定初始的缩放值的话,那么iphone和ipad会自动计算initial-scale这个值,以保证当前layout viewport的宽度在缩放后就是浏览器可视区域的宽度,也就是说不会出现横向滚动条。好比说,在iphone上,咱们不设置任何的viewport meta标签,此时layout viewport的宽度为980px,但咱们能够看到浏览器并无出现横向滚动条,浏览器默认的把页面缩小了。根据上面的公式,当前缩放值 = ideal viewport宽度  / visual viewport宽度,咱们能够得出:

      当前缩放值 = 320 / 980

也就是当前的initial-scale默认值应该是 0.33这样子。当你指定了initial-scale的值后,这个默认值就不起做用了。

总之记住这个结论就好了:在iphone和ipad上,不管你给viewport设的宽的是多少,若是没有指定默认的缩放值,则iphone和ipad会自动计算这个缩放值,以达到当前页面不会出现横向滚动条(或者说viewport的宽度就是屏幕的宽度)的目的。

11    12     13

 

二、动态改变meta viewport标签

第一种方法

可使用document.write来动态输出meta viewport标签,例如:

document.write('<meta name="viewport" content="width=device-width,initial-scale=1">')

第二种方法

经过setAttribute来改变 

<meta id="testViewport" name="viewport" content="width = 380">
<script>
var mvp = document.getElementById('testViewport');
mvp.setAttribute('content','width=480');
</script>

 

 

安卓2.3自带浏览器上的一个bug

复制代码
<meta name="viewport" content="width=device-width">

<script type="text/javascript">
alert(document.documentElement.clientWidth); //弹出600,正常状况应该弹出320
</script>

<meta name="viewport" content="width=600">

<script type="text/javascript">
alert(document.documentElement.clientWidth); //弹出320,正常状况应该弹出600
</script>
复制代码

测试的手机ideal viewport 宽度为320px,第一次弹出的值是600,但这个值应该是第行meta标签的结果啊,而后第二次弹出的值是320,这才是第一行meta标签所达到的效果啊,因此在安卓2.3(或许是全部2.x版本中)的自带浏览器中,对meta viewport标签进行覆盖或更改,会出现让人很是迷糊的结果。

 

7、结语

说了那么多废话,最后仍是有必要总结一点有用的出来。

首先若是不设置meta viewport标签,那么移动设备上浏览器默认的宽度值为800px,980px,1024px等这些,总之是大于屏幕宽度的。这里的宽度所用的单位px都是指css中的px,它跟表明实际屏幕物理像素的px不是一回事。

第2、每一个移动设备浏览器中都有一个理想的宽度,这个理想的宽度是指css中的宽度,跟设备的物理宽度没有关系,在css中,这个宽度就至关于100%的所表明的那个宽度。咱们能够用meta标签把viewport的宽度设为那个理想的宽度,若是不知道这个设备的理想宽度是多少,那么用device-width这个特殊值就好了,同时initial-scale=1也有把viewport的宽度设为理想宽度的做用。因此,咱们可使用

<meta name="viewport" content="width=device-width, initial-scale=1">
来获得一个理想的viewport(也就是前面说的ideal viewport)。

为何须要有理想的viewport呢?好比一个分辨率为320x480的手机理想viewport的宽度是320px,而另外一个屏幕尺寸相同但分辨率为640x960的手机的理想viewport宽度也是为320px,那为何分辨率大的这个手机的理想宽度要跟分辨率小的那个手机的理想宽度同样呢?这是由于,只有这样才能保证一样的网站在不一样分辨率的设备上看起来都是同样或差很少的。实际上,如今市面上虽然有那么多不一样种类不一样品牌不一样分辨率的手机,但它们的理想viewport宽度概括起来无非也就 320、360、38四、400等几种,都是很是接近的,理想宽度的相近也就意味着咱们针对某个设备的理想viewport而作出的网站,在其余设备上的表现也不会相差很是多甚至是表现同样的。

相关文章
相关标签/搜索