前言:原文地址:A tale of two viewports — part two (quirksmode.org)
目录
移动端浏览器的问题(The proble of mobile browsers)
两个viewports(The two viewports)
在这个系列,我将会探索viewports和各种重要元素的宽度,例如html元素,window和屏幕。
在这个页面,我们讨论移动端浏览器。如果你完全是个移动端新手,我建议你先去阅读一下我前面写的关于桌面浏览器的内容,以便在熟悉的环境中搭建舞台。
移动端浏览器的问题(The proble of mobile browsers)
比较移动端浏览器和桌面浏览器,很明显,它们最大的不同是设备屏幕的大小。移动浏览器显示的桌面优化网站明显少于桌面浏览器;要么缩小文字到无法阅读,或者只展示适合屏幕的一小部分网站的内容。
移动端的屏幕远小于桌面屏幕;试想一下屏幕最大限度的宽度是400px,有时更小。(有些手机被报道有更大的宽度,但是他们是在说谎———或者最新给我们得消息是无用的。)
一些中间层的平板设备例如iPad 或 传说中的HP webOS--将会桥接桌面端和移动端的鸿沟,但是这并不能改变基本的问题。网站也必须运行在移动设备上,所以我们不得不让它们在小屏幕上正常运行。
最重要的问题集中在CSS上,尤其是viewport的尺寸。如果我们一对一拷贝桌面模式,那么,我们的CSS将会不奏效。
让我们回到我们有宽度为10%的元素上。如果移动浏览器要做和桌面浏览器同样的事情,它们最大程度使该元素的宽度达到40px;这样就太窄了。你的流式布局将会被严重挤压变形。
一个解决方法就是为移动端浏览器建立一个特殊的网站。除了是否应该这样做的基本问题,实际问题是只有极少数网站所有者能够充分参与到专门针对移动设备的服务中。
移动浏览器供应商想要提供它们的客户尽可能最好的体验,那么就意味着“尽可能和桌面端浏览器越像。”因此一些花招是必要的。
两个viewports(The two viewports)
因为viewport太窄而不能为最基本的css布局服务。最明显的方法是让viewport更宽。那么,就让viewport分裂成两部分:visual viewport和layout viewport.
George Cummins在Stack Overflow中将基本的概念解释的很好:
“想象一下viewport布局不用改变大小和形状可以像一张大的图片一样。现在你有一个小框架通过它你可以看到一个大的图片。小框架被不透明的物质包围着这让你的视野很模糊,但是这是整个大图片的一部分。你所看到图片的这部分的内容就是通过visual viewport框架看到的。您可以在按住这个框架(缩小)的同时远离大图像,以立即查看整个图像,或者你可以靠近(放大)只看到大图片的一部分。你也可以改变框架的方向,但是这个大图片(layout viewport)的形状和大小不会改变。”
Visual viewport是当前显示在屏幕上的页面的一部分。用户可以滚动改变他看到的页面的部分 或者通过缩放改变 visual viewport 的大小。
然而,CSS布局,尤其是宽度的百分率的计算与layout viewport 相关,这就比visual viewport 宽的多。
但是,<html>元素最初是根据 layout viewport的宽度计算的,你的css被理解为屏幕比手机屏幕更宽。这是为了保证网站的布局行为同桌面浏览器一样。
那么 layout viewport 有多宽呢?每种浏览器都不相同。Safari iPhone 使用980px,Opera 850px,android webkit 800px; IE 974px.
一些浏览器有特殊的表现形式:
Symbian Webkit试图让layout viewport 等同于visual viewport,是的,这就意味着元素的宽度百分率会表现的很奇怪。然而,如果页面因为绝对宽度不适合visual viewport 浏览器会拉伸layout viewport 到850px最大限度。 Samsung WebKit 让layout viewport 的宽度同元素的最大宽度一致。
BlackBerry 在100%缩放下 layout viewport 等同于visual viewport.
Zooming
Layout viewport 和visual viewport都是以CSS像素为单位测量的。但是当visual viewport 的尺寸通过缩放改变(如果你放大,更少的CSS像素在屏幕上),layout viewport 的尺寸保持不变。(如果没有,您的页面会随着百分比宽度的重新计算而不断回流)
理解 layout viewport
为了理解layout viewport 的大小,我们要看看当页面拉到最小时发生了什么。当页面完全缩小时,许多移动浏览器最初展示任何内容。
关键是:浏览器选择了layout viewport 的尺寸,以便在完全缩小模式下完全覆盖屏幕(因此与visual viewport相等)。
在最大限度的缩小模式下,layout viewport 的宽度和高度等于在屏幕上显示的任何内容。当用户放大时这些尺寸保持不变。
Layout viewport 宽度保持不变。如果你旋转手机,visual viewport 会改变,但是浏览器通过轻微的放大会适应新的方向所以layout viewport 又和visual viewport的宽度一样。
这样会影响layout viewport 的高度,该高度大大低于纵向的高度。但是 网页开发者不必在乎高度,只在乎宽度。
测量layout viewport
现在我们有两个viewport 需要测量。幸运的是浏览器战争遗留给我们两个属性对。
Document.documentElement.clientWidth 和-height 包含layout viewport的大小。
测量visual viewport
Visual viewport 用window.innerWidth/Height测量。很明显,当用户缩放浏览器时测量值会改变,因为屏幕上容纳更多或者更少的CSS像素。
不幸的是这是一个不兼容的领域;许多浏览器依然增加对visual viewport 测量的支持。仍然在其他属性对中没有浏览器存储这个测量值,所以我猜测window.innerWidth/Height 时一个标准,尽管支持很差。
屏幕(The screen)
与桌面上一样,screen.Width/Height以设备像素为单位给出屏幕的大小。同桌面一样,作为网页开发者你不需要这些信息。你不对屏幕的物理大小感兴趣,但是取决于它当前适合多少CSS像素。
缩放水平(The zoom level)
直接读出缩放水平不容易,但是可以用window.innerWidth分割screen.width.当然那只有在浏览器对两个属性对都支持的情况下。
幸运的是缩放水平并不重要。你需要知道的是当前屏幕里有多少CSS像素。可以用window.innerWidth来获取———如果浏览器正确支持的话
滚动偏移量(scrolling offset)
你需要知道的是visual viewport 相对于layout viewport的当前位置。这就是偏移量,只在桌面上,偏移量存储在window.pageX/YOffset.
<html>元素
只在桌面端浏览器,document.documentElement.offsetWidth/Height给出<html>元素以CSS像素为单位的大小尺寸。
媒体查询
媒体查询同桌面一样。Width/height使用layout viewport作为参照物以CSS像素为单位测量,device-width/height用设备屏幕作为参照物以设备像素为单位。
换句话说,width/height反应document.documentElement.clientWidth/Height的值,同时device-width/height反应screen.width/height的值。(事实上所有浏览器都这样做尽管反应的值不正确。)
现在对于网页开发者哪个测量值更有用呢?关键是我不知道。
我起初认为device-width更重要,因为它给了我们一些可能要使用的设备的信息。譬如你可以顺应设备的宽度变更你布局的宽度。然而你也可以用<metaviewport>来做;不必非要用device-width进行媒体查询。
所以宽度居然是媒体查询最重要的信息吗?也许是;它提供了一些线索,说明浏览器供应商认为该设备上的网站宽度合适。但这相当模糊,而媒体查询宽度并没有提供任何其他信息。
所以我犹豫不决。目前我认为媒体查询无论是对桌面、平板还是移动设备的计算很重要,但是对区分各种平板或者移动设备并不是很有用。
事件坐标
事件坐标或多或少同桌面一样。不幸的是在12个测试过的浏览器中只有Symbian Webkit 和Iris得到三个准确的值。其他浏览器或多或少有一些问题。
pageX/Y 仍然是相对于页面的CSS像素,并且显然这是三个属性对中最有用的,仅仅在桌面端。
clientX/Y 是相对于visual viewport的CSS像素。这很明显,尽管我不完全确定这有什么好处。
screenX/Y是相对于屏幕的设备像素。当然这与clientX/Y相关,设备像素是没有用的。我们不用担心screenX/Y;它跟在桌面上一样没有用处。
Meta viewport
最后,我们来讨论<meta name=”viewport”content=”width=320”>;最初是苹果的扩展但同时被越来越多的浏览器复制。那就意味着改变layout viewport的大小。为了理解它的必要性,我们后退一步。
假设你建了一个页面,没有给你的元素宽度。现在它们被拉伸到layout viewport100%的宽度。大多数浏览器缩小展示整个layout viewport在屏幕上,产生像这样的效果:
所有的用户会立刻放大,这是可行的,但是大多数浏览器会保持元素的完整性,这将是文本内容难以阅读。
(这儿有个重要的例外是android WebKit,它实际减少了包含文本元素的大小因此适合屏幕。这绝对很明智,我觉得其他浏览器能够参考这种方式。我将会在之后记录。)
现在你可以试着设置html{width:320px;}.现在<html>元素收缩,其他所有元素也随之收缩,现在占据了320px的100%。
在用户放大时同样有效,但是起初当用户面对一个缩小的不包含任何内容的页面时没有效果。
为了避开这个问题,Apple发明了meta viewport标签。当你是设置<meta name=”viewport“ content =”width=320”>你设置了layout viewport的宽度到320px.现在页面的初始状态是正确的。
你可以设置layout viewport 的宽度到任何你想要的尺寸,包括 device-width.最后一个出现在屏幕上。宽度(设备像素)作为参考并相应的调整layout viewport的大小。
尽管这儿有一个隐藏的困难。有时候正式的screen.width不能讲得通因为像素数太高了。例如,Nexus One的正式宽度是480px,但是谷歌工程师已经决定,当使用device-width时给layout viewport 的宽度为480px那就太大了。
如果像传言的那样,新款iPhone将采用更大的像素数(这不一定等于更大的屏幕!),如果苹果复制这种行为,我不会感到惊讶。也许最终设备宽度将仅意味着320px。
相关的研究
不久会研究几个相关的话题:
- position:fixed.正如我们所知,一个固定定位的元素是相对于viewport定位的。但是相对与哪个viewport呢?我做了研究在这篇文章里:The fifth position value - QuirksBlog (quirksmode.org)
- 其他媒体查询:dpi、方向,纵横比。Dpi尤其是一个重灾区,不仅仅是因为所有浏览器公布96dpi,这通常是错误的,而且我还不完全确定对于网页开发者哪个值是他们最感兴趣的。
- 当一个元素比layout viewport/HTML元素宽会发生什么?比方说我插入一个宽度为1500px的元素到我的一个测试页面?元素将会溢出HTML元素(overflow:visible),但是那就意味着实际的viewport可以变得比layout viewport的宽度大。此外,当这样发生时,老的android(Nexus One)使HTML元素扩大。