本文主要转自:移动浏览器的viewport ,部分内容有补充修改。
对于移动web开发,最好了解一下viewport的概念,在quirksmode.org有两篇文章详细介绍了它,A tale of two viewport(1 2),感觉非常好,本来想翻译的,但这两篇文章实在太长了,没耐性,于是抽取了其中重点讲viewport的部分,用半翻译半自己写的方式写出来,这也是为了让自己能够理解得更好一些。
其中CSS像素和设备像素的概念,还有js获取各种宽高和位置的内容都没有提及,要想了解得更清楚还是推荐看看那两篇文章。以下图片均来自quirksmode.org。
桌面浏览器
先说说桌面浏览器上viewport的概念,在桌面浏览器上viewport就是浏览器内容的可视范围,它决定了<html>元素的默认宽高。举个例子:
在一个流动布局的页面上,你给侧栏设置了30%,放在<body>下,正常情况下你拖动浏览器,改变浏览器的大小,这个侧栏会自动调整宽度使它的宽度为浏览器宽度的30%,那么这个自动调整的过程具体是怎样的呢?
这个侧栏会获取父元素的宽度,乘以30%得到自己的宽度。那问题就变成这个侧栏的父元素<body>宽度的取值问题。一般情况下,一个块级元素的宽度会自动伸展到父元素的宽度,所以这里<body>的宽度等于<html>的宽度。那么<html>的宽度又由谁决定?理论上,如果没有给<html>指定CSS宽度,那它的宽度由viewport决定,于是这里30%的宽度就是浏览器viewport的宽度。
viewport的宽高不仅在窗口resize的时候会改变,在缩放的时候也会变化。例如:
这个页面,有一个宽度100%的nav和宽度800px的test元素,把窗口宽度调整到800px,页面上两个元素nav和test大小是一致的。对页面通过浏览器缩放放大一倍,此时viewport的css宽度缩小为400px(设备宽度不变),nav元素的css宽度也就缩小到了400px,test元素仍然是800px,比nav大了一倍。
viewport不是HTML的一部分,无法用css控制它,对桌面浏览器来说,viewport只是一个拥有浏览器可视宽高(css像素)属性的东西。
移动浏览器
移动设备比桌面设备屏幕小很多,如果把桌面浏览器viewport的概念照搬过来会出现什么后果?
假设流动布局的网站,一般给侧栏设置30%,那么假设移动浏览器宽高是320*480,那么这个侧栏实际拥有的宽度只有不到100px,放几个字都不够,这会让你的网站显得很糟糕,一大票在桌面浏览器结构良好的网页在移动浏览器上都会惨不忍睹。
移动浏览器的设计者就希望移动设备上网页的显示能尽可能地接近桌面浏览器,于是有了这么两个概念:visual viewport和layout viewport。
visual viewport就是浏览器当前显示的部分页面,可以通过拖动改变页面显示的部分,通过放大缩小改变visual viewport的大小。
layout viewport就是提供给CSS计算的viewport,相当于桌面浏览器的viewport,不同的是layout viewport跟当前浏览器可视范围无关系,浏览器怎么缩放都与它无关,它是一个给定的值。
不同设备给layout viewport定了不同的默认值,宽度上大概是:Safari 980px,Opera 850px,Android Webkit 800px,IE 974px,高度根据设备屏幕的宽高比计算。(实际上viewport的高度几乎没用,可以忽略之)
这样提供给css计算的viewport宽高就与桌面浏览器相近了,页面计算渲染出来的效果跟桌面浏览器几乎一致。页面放大缩小不会影响到layout viewport,也就是不会影响到页面渲染。
在移动浏览器上,所有页面打开时默认visual viewport = layout viewport,也就是最小缩放,例如用mobile safari打开一个页面,无论页面内容如何,都会显示980px宽度的内容。
修改layout viewport
可以通过在<head>上写<meta>标签改变浏览器的layout viewport,如果专门针对移动浏览器设计页面,那最常用的就是设置layout viewport宽度为设备宽度,或者设置initial-scale,并设置不可缩放,这样移动浏览器就始终以1:1的方式渲染显示页面,无需理会缩放,可以像桌面浏览器那样进行精确的开发。
<meta name=”viewport” content=”width=device-width, user-scalable=no”>
<meta name=”viewport” content=”initial-scale=1.0, user-scalable=no”>
Viewport语法为:
<meta name="viewport" content=" height = [pixel_value | device-height] , width = [pixel_value | device-width ] , initial-scale = float_value , minimum-scale = float_value , maximum-scale = float_value , user-scalable = [yes | no] , target-densitydpi = [dpi_value | device-dpi | high-dpi | medium-dpi | low-dpi] "/>
height
和 width 相对应,指定高度。
width
控制 viewport 的大小,可以指定的一个值或者特殊的值,如 device-width 为设备的宽度(单位为缩放为 100% 时的 CSS 的像素)。
initial-scale
初始缩放。即页面初始缩放程度。这是一个浮点值,是页面大小的一个乘数。例如,如果你设置初始缩放为“1.0”,那么,web页面在展现的时候就会以target density分辨率的1:1来展现。如果你设置为“2.0”,那么这个页面就会放大为2倍。
maximum-scale
最大缩放。即允许的最大缩放程度。这也是一个浮点值,用以指出页面大小与屏幕大小相比的最大乘数。例如,如果你将这个值设置为“2.0”,那么这个页面与target size相比,最多能放大2倍。
user-scalable
用户调整缩放。即用户是否能改变页面缩放程度。如果设置为yes则是允许用户对其进行改变,反之为no。默认值是yes。如果你将其设置为no,那么minimum-scale 和 maximum-scale都将被忽略,因为根本不可能缩放。
所有的缩放值都必须在0.01–10的范围之内。
target-densitydpi
一个屏幕像素密度是由屏幕分辨率决定的,通常定义为每英寸点的数量(dpi)。Android支持三种屏幕像素密度:低像素密度,中像素密度,高像素密度。一个低像素密度的屏幕每英寸上的像素点更少,而一个高像素密度的屏幕每英寸上的像素点更多。Android Browser和WebView默认屏幕为中像素密度。
下面是 target-densitydpi 属性的 取值范围
- device-dpi –使用设备原本的 dpi 作为目标 dp。 不会发生默认缩放。
- high-dpi – 使用hdpi 作为目标 dpi。 中等像素密度和低像素密度设备相应缩小。
- medium-dpi – 使用mdpi作为目标 dpi。 高像素密度设备相应放大,低像素密度设备相应缩小。 这是默认的target density.
- low-dpi -使用mdpi作为目标 dpi。中等像素密度和高像素密度设备相应放大。
- <value> – 指定一个具体的dpi 值作为target dpi. 这个值的范围必须在70–400之间。
为了防止Android Browser和WebView 根据不同屏幕的像素密度对你的页面进行缩放,你可以将viewport的target-densitydpi 设置为 device-dpi。当你这么做了,页面将不会缩放。相反,页面会根据当前屏幕的像素密度进行展示。在这种情形下,你还需要将viewport的width定义为与设备的width匹配,这样你的页面就可以和屏幕相适应。
例如:
<!--(设置屏幕宽度为设备宽度,禁止用户手动调整缩放)--> <meta name="viewport" content="width=device-width,user-scalable=no" /> <!--(设置屏幕密度为高频,中频,低频自动缩放,禁止用户手动调整缩放)--> <meta name="viewport" content="width=device-width,target-densitydpi=high-dpi,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
高分辨率移动设备
移动浏览器的分辨率与移动设备本身的分辨率并不一定一致。现在市面上有很多高分辨率的手机,例如3.7寸的Nexus One手机分辨率达到800*480,3.5寸的iphone4分辨率达到960*640。但如果以这样实际的值提供给浏览器进行计算和渲染,那会有两个问题。
- 与其他移动设备差别太大,导致之前专门设计的页面无法兼容
- 按照这样的分辨率去设计页面时,会乱了套,例如12px的字体在普通移动设备上显示正常,但在高分辨率设备上显得太小无法分辨,必须手动把它调高N倍。
于是这些高分辨率设备没有提供真实的像素值给浏览器,而是通过比例缩放的。例如iphone4缩小2倍(480*320),Nexus缩小1.5倍(533*320),反过来说就是每个页面都默认放大X倍显示。所以以前一个针对iphone3GS以下设计的网页,在iphone4上表现完全一致,只是更精致了。