移动web开发之viewport的深入理解

之前已经讲解了很多关于移动开发和响应式布局的基础知识,今天许小珂就来讲讲最后一个基础概念:视口

在桌面上,视口的宽度等同于浏览器窗口的宽度,高度即为浏览器窗口的高度。而在浏览器宽度通常为240px~640px的移动设备上也这样做的话,则布局会出现很大的问题。为了适应为桌面浏览器设计的网站(这类网站使用固定布局,页面主体的宽度通常显式地设置在1000px上下,一般为960px),浏览器出现了布局视口概念。与桌面浏览器不同的是,浏览器默认的布局视口宽度与浏览器宽度完全独立。

布局视口
那么什么是布局视口呢?其实当加载网站时手机浏览器默认为我们做了两件事情

将页面渲染在一个980px(iOS)的layout viewport;
缩放,渲染之后通过缩放让我们看到整个网站的全貌;
而这个980px就是布局视口(layout viewport),它是由设备浏览器决定的。下图列出了一些设备上浏览器的默认viewport的宽度。

移动web开发之viewport的深入理解
这个layout viewport的宽度可以通过 document.documentElement.clientWidth 来获取。然而,layout viewport 的宽度是大于浏览器可视区域的宽度的,所以我们还需要一个viewport来代表浏览器可视区域的大小即visual viewport。visual viewport的宽度可以通过window.innerWidth 来获取,但在Android 2, Oprea mini 和 UC 8中无法正确获取。为什么渲染页面时要有layout viewport?

其实这样做的目的主要是为了“排版正确”,伪造一个大的980px的layout viewport先让排版正确,不至于样式乱套,然后在通过缩放使我们在移动端看到正确的排版。

当然使用默认的980px布局视口有一些缺点:

  1. 宽度不可控制,不同系统不同设备的默认值都可能不同;
  2. 页面缩小版显示,交互不好;
  3. 链接不可点;
  4. 有缩放,缩放后又有滚动;

三种视口
总结下来其实视口可以分为3个:度量视口、布局视口和理想视口。

  1. visual viewport(度量/视口);
  2. layout viewport(布局viewpoint);
  3. Ideal viewport理想视口就是布局视口在一个设备上的最佳尺寸。

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

利用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这个属性了,所以这个属性我们要避免进行使用 。

把当前的viewport宽度设置为 ideal viewport 的宽度
要得到ideal viewport就必须把默认的layout viewport的宽度设为移动设备的屏幕宽度。因为meta viewport中的width能控制layout viewport的宽度,所以我们只需要把width设为width-device这个特殊的值就行了。

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

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

可以看到通过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吗?事实证明,的确是这样的。下图是各大移动端的浏览器当设置了后是否能把当前的viewport宽度变成 ideal viewport 的宽度的测试结果。

移动web开发之viewport的深入理解
测试结果表明 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">

总之,关于viewport的基础知识许小珂也就总结了这么多,如果想要更加深入的理解可以找许小珂探讨,亦或是查询更专业的资料和书籍。同样也希望这篇文章能够帮助到大家。

在文章结尾推荐大家可以看看慕课网的这篇视频教程,满满的都是干货:Hello,移动WEB