关于viewport的一些思考

在写html时我们经常会看到头部有一列的meta标签,因此最近总结了一些比较常用的http-equiv属性和name属性,在前一篇文章中可以查阅到。这其中最有意思的就是viewport了,这个属性决定了用户访问你的网站时的第一体验。下面我们按照桌面浏览器以及移动浏览器两个板块来学习下viewport。

桌面浏览器

设备像素和CSS像素

设备像素是固定的,可以从screen.width/height读出,而CSS像素的可见大小是可以变化的。如果我们给一个元素设置了width:512px的属性,且显示器是1024px宽,当我们将页面放大一倍时,此时该元素将占满整个宽度,每个像素的宽度都被拉伸到原来的一被大,也就是每个像素占着2个实际像素的空间,因此占满整个屏幕。在缩放比例100%的情况下一个CSS像素完全等于一个设备像素。

屏幕尺寸

意义:用户屏幕的整体大小。
度量:设备像素。
获取:screen.width/height。

窗口尺寸

意义:浏览器窗口的整体大小,包括滚动条。对窗口进行放大或缩小时值会变。
度量:CSS像素。
获取:window.innerWidth/Height。

滚动距离

意义:页面的滚动距离,具体指滚动条距顶部的距离。
度量单位:CSS像素。
滚动距离的度量方式为css像素,可以通过window.pageXOffset/pageYOffset来获取。

viewport

我们都知道块级子元素的宽度默认为块级父元素的100%,body的宽度默认来自于html的宽度,那么html的宽度来自哪呢?其实html是在一个叫viewport的假想机制下进行渲染的,在桌面浏览器中,这个viewport的宽度就等于浏览器窗口的宽度(不包括滚动条)。
既然html的宽度来自于viewport的宽度,而documentElement指向html元素,那么我们可以通过document.documentElement.clientWidth来得到viewport的宽度。但这里有一个特殊的规则,即使设定了html的宽度,clientWidth还是指向viewport的宽度。
若想真正获取html的宽度,我们可以通过另一个方法document.documentElement.offfsetWidth,该属性始终都指向html的宽度值。

事件中的坐标

pageX\Y提供了相对于html元素的以css像素度量的坐标。
clientX/Y提供了相对于viewport的以css像素度量的坐标
screenX/Y提供了相对于屏幕的以设备像素进行度量的坐标。

媒体查询

媒体查询使用的宽高是viewport的宽高而不是设备的宽高。因为我们感兴趣的是基于css像素的页面,而不是基于设备像素的页面。


移动浏览器

两个viewport

如果我们继续按照在桌面浏览器中渲染页面的方式来设计移动浏览器,那么我们的站点将陷入一个无比尴尬之地,要么为移动端单独设计网页,要么页面在移动端的显示非常拥挤。这时浏览器厂商尝试了一种比较有利的做法,他们把浏览器中的一个viewport变成两个viewport,一个是layout viewport,另一个则是visual viewport。先来看这两个概念的定义。

layout viewport的宽度和高度等于在最大限度缩小的模式下屏幕上所能显示的任何内容的尺寸。
visual viewport是页面当前显示在屏幕上的部分。用户可以通过滚动来改变他所看到的页面的部分,或者通过缩放来改变visual viewport的大小。

viewport.PNG

我们可以把layout viewport想象成一个后花园,后花园的大小不会变(不太严谨,高度在设备旋转后会微变)
,且带有一个可移动的门,我们从这个门里所看到的景物就是visual viewport, 当我们走进(放大)这个门时,visual viewport就会变大,当我们远离(缩小)时,visual viewport就会变小。此外我们还可以通过移动这扇门来观察到后花园的每个角落。

此时,html不再像桌面浏览器中那样继承于viewport,移动浏览器厂商让html的宽度基于layout viewport这个固定大小的后花园,而设备屏幕则相当于我们的这个移动门,屏幕里的内容就是我们的visual viewport。显然,内容的尺寸会发生变化,visual viewport的大小也会随之变化。

度量layout viewport

document.documentElement.clientWidth/Height

度量visual viewport

window.innerWidth/Height

屏幕

依然是 screen.width/height

缩放比例

可以通过以screen.width除以window.innerWidth来获取它的值。

滚动距离

window.pageX/YOffset 表示visual viewport相对于layout viewport的位置。

html元素

document.documentElement.offsetWidth/Height可以获取html的宽高。

媒体查询

width/height使用layout viewport做为参照物,并且以CSS像素进行度量,device-width/height使用设备屏幕,并且以设备像素进行度量。

事件坐标

同桌面浏览器工作方式

viewport meta标签

意义:设置layout viewport的宽度。
度量单位:CSS像素。
铺垫辣么长,终于到了我们的重点了。假如我们创建一个简单的页面,且没有设置元素宽度,那么页面就会以拉伸的方式填满layout viewport,继而再在整个屏幕上显示,此时页面的内容将会非常小。因为大多数的layout viewport被设置为980px。viewport标签则提供了我们可以修改其宽度的接口。

1
<meta name="viewport" content="width=320">

通过将viewport(实为layout viewport)设置为320px,我们的html在移动端则基于320px的框架去布局,这样既可得到更人性化的结果。
1
<meta name="viewport" content="width=320, intial-scale=1">

intial-scale则表示页面首次被显示是可视区域的缩放级别,一般开始时都不会是1,其公式为:
1
当前缩放值 = ideal viewport宽度 / visual viewport宽度

这里的ideal viewport宽度为移动设备的屏幕宽度(以CSS像素定义),所有iphone的屏宽都为320px。因此initial-scale=1width=320有一样的效果,但因为这两种写法在不同场景各有瑕疵,因此一般都同时使用,若值不同则采取较大方式显示。
总的来说,viewport是针对移动端设备为了对桌面站点更友好而设计的一种技巧性api,但不同的浏览器还是有着大大小小的差异,使用中还得根据需求采取不同的方式。