原作者: Peter-Paul Koch
原文地址: www.quirksmode.org/mobile/view...
在这个小系列中, 我会解释视口以及各种重要元素的宽度是如何计算的, 如<html>
元素, window 和 screen.
本文讲的是移动端浏览器. 如果你完全不熟悉移动端, 我建议你先阅读系列的第一部分(第一部分的的翻译可以看[译] 两种视口的故事(一)): 关于桌面浏览器的文章, 以便做一些基础准备.
移动端浏览器的问题
我们对比移动端和桌面端浏览器的时候, 最明显的区别就是屏幕尺寸. 桌面端网页在移动端浏览器上相对桌面浏览器来说, 所展示的网站内容明显少很多, 要么是缩小到文字都看不清, 要么是为了适应屏幕, 只展示网站的一部分.
移动端屏幕要比桌面端屏幕小很多, 设想一个屏幕最宽 400px, 有时还更小. (某些手机给出的宽度偏大, 但其实是设备撒了谎------至少提供的是无用信息.)
处于中间的平拍设备, 比如 iPad 或传闻的基于 HP webOS 的设备会弥合桌面端和移动端之间的差异, 但是这仍然不能解决根本问题. 因为网站必须在移动端设备上也要良好运行, 所以我们不得不让其在小尺寸屏幕上也能有良好展示.
最主要的问题在于 CSS, 特别是视口尺寸. 如果照搬桌面端的模式的话, 我们的 CSS 样式简直将会失败透顶.
让我们回到 width: 10%
的边栏. 如果移动端浏览器与桌面端浏览器行为完全一致的话, 侧边栏元素的宽度最高就是 400px, 侧边栏就变得太窄了. 流式布局(的网页)看起来就被压扁了.
一种解决方案是建一个移动端浏览器的专用网站. 抛开你是否应该那样做的这个基本问题不谈, 实际问题是, 只有极少数网站所有者充分了解移动端设备的适配.
移动端浏览器供应商想要为客户提供最佳体验, 目前来说意味着"尽可能想桌面浏览器那样". 有必要使用一些技巧.
两种视口
视口太窄导致无法作为 CSS 布局的基础. 最明显的方式是让视口更宽. 也就是说, 需要分为两部分: 可见视口和布局视口.
George Cummins 在 Stack Overflow这里对基本概念做出了最佳解释:
把布局视口想象为一副很大的, 尺寸固定的图片. 然后想想你通过一个小框去看这张大图片. 小框周围都是不透明的, 让你无法看清全貌, 而只能看见图片的部分区域. 通过小框你所看到的这部分区域就是可见视口. 拿着小框的时候, 你可以后退(缩小), 以便看清图片全貌, 或者也可以走进(放大)只看一部分. 你也可以旋转小框, 但大图的尺寸和形状(视图视口)都没改变.
也可以参考 Chris 的解释.
可见视口是此时屏幕上所显示的页面部分内容. 用户会滚动页面看页面的其他部分, 或者缩放以改变可见视口尺寸.
然而,CSS 布局中,特别是百分比宽度,是相对于布局视口计算的,它比可见视口宽得多。
因此,元素最初采用布局视口的宽度,并且 CSS 被渲染成好像屏幕比手机屏幕宽得多。这可以确保你网站的布局和桌面端的保持一致。
布局视窗有多宽?这因浏览器而异。Safari iPhone 使用 980px, Opera 850px, Android WebKit 800px, IE 974px。
一些浏览器比较特殊:
-
Symbian WebKit 试图保持布局视窗等于视觉视窗,这意味着具有百分比宽度的元素可能会表现得很奇怪。但是,如果页面由于绝对宽度而无法放入视觉视口,则浏览器将布局视口拉伸到最大 850px。
-
三星 WebKit(在 bada 上)使布局视口与最宽元素一样宽。
-
在黑莓上,布局视窗等于 100%缩放的视觉视窗。这一点不会改变。
缩放
显然,两个视口都是以 CSS 像素来衡量的。可虽然视觉视口尺寸随着缩放而改变(如果放大,屏幕上容纳的 CSS 像素就会减少),但布局视口尺寸保持不变。(如果他们不这样做,你的页面将不断回流,因为要重新计算百分比宽度。)
理解布局视口
为了理解布局视窗的大小,我们必须看看当页面完全缩小时会发生什么。许多移动浏览器最初以整个页面完全缩小的模式显示页面。
原因是: 浏览器选择布局视口的尺寸,使页面以完全缩小模式完全覆盖屏幕(因此等于视觉视口)。
因此,布局视口的宽高等于在最大缩小模式下在屏幕上显示的内容。当用户放大时,这些维度保持不变。
布局视口宽度总是相同的。如果你旋转手机,视觉视口会改变,但是浏览器会通过稍微放大来适应这个新的方向,这样布局视口就会再次和视觉视口一样宽。
这会影响视图视口的高度, 现在比竖屏模式要小得多. 但 web 开发者不关心高度, 只关心宽度.
布局视口尺寸
我们现在要测量这两个视口的尺寸。多亏了浏览器大战给予我们的两对属性。
document.documentElement.clientWidth 和 Height 包含布局视口的尺寸。
方向与高度有关,但与宽度无关。
视觉视口尺寸
至于视觉视口,它是由 window.innerWidth/Height 衡量的。显然,当用户缩小或放大时,测量值会发生变化,因为屏幕上容纳更多或更少的 CSS 像素。
不幸的是,兼容性并不好; 许多浏览器仍然需要添加获取视觉视口尺寸的支持。但是,没有浏览器将这个度量值存储在任何其他属性对中,所以我猜是 window.innerWidth/Height 是一种标准,尽管支持性很差。
屏幕
在桌面浏览器中, screen.width/height 可获取屏幕设备的像素尺寸. 在桌面端, 作为 web 开发者你从不会关心这个. 你对设备的物理尺寸并不感兴趣, 而是当前屏幕上有多少 CSS 像素.
缩放比例
直接读取缩放比例是不可能的, 但你可以通过 screen.width 除以 window.innerWidth 来获取. 当然, 必须是这两个属性都支持.
滚动位移
你也需要知道当前视觉视口相对于布局视口的位置. 这就是滚动位移, 跟桌面端一样, 可通过 window.pageX/YOffset 获取.
元素
跟桌面端一样, document.documentElement.offsetWidth/Height
是元素的 CSS 像素尺寸.
媒体查询
媒体查询与桌面端一致, width/height 以布局视口作为参考 ,也是以 CSS 像素来衡量, device-width/height 以显示屏作为参考, 以设备像素来衡量.
也就是说, width/height 映射了 document.documentElement.clientWidth/Height 的值, device-width/height 映射了 screen.width/height 的值.(在所有浏览器上均有效, 即使代表的值可能是错误的.)
那么, 对于 web 开发者来说那种更有效呢? 答案是: 我也不知道.
我最初以为 device-width 是最佳之选, 因为它提供一些我们可能会用到的设备信息. 例如, 你可以根据不同设备宽度调整布局宽度. 然而, 你可以指定<meta viewport>; 并不一定在媒体查询中使用 device-width.
那么 width 会是媒体查询最终之选吗? 或许是; 它提供了一些信息------浏览器厂商认为当前设备上网页的合适宽度.但这也相当模糊, 媒体查询使用 width 实际上并不会提供其他信息.
所以我没下定论. 我认为媒体查询对于判断是否为桌面设备, 平板或移动设备比较重要, 但用来分辨不同类型平板和移动设备并没什么用.
事件坐标
或多或少与桌面相同。不幸的是,在 12 个用于测试的浏览器中,只有两个,Symbian WebKit 和 Iris,完全正确地获取这三个值。其他浏览器或多或少都有严重的问题。
与桌面端一样, pageX/Y 仍是相对于页面的 CSS 像素值, 这是三对属性中最有用的。
clientX/Y 是相对于视觉视口的 CSS 像素值。这有用,尽管我不太确定这有什么好处。
screenX/Y 相对于屏幕的设备像素值. 当然这个值和 clientX/Y 的值一样, 也没什么用. 因此我们不必担心 screenX/Y; 几乎没什么用.
meta viewport
最后,我们来讨论一下<meta name="viewport" content="width=320">; 这最初是苹果的扩展,但同时被许多浏览器复用。这意味着调整布局视口的尺寸。为了理解其必要性, 我们来回顾一下历史。
假设你写了一个简单的页面, 而且没有给元素设置 width. 此时, 他们会拉甚至布局视口的 100%宽度. 大多数浏览器会缩小页面, 在屏幕上展示整个布局视口. 如下图:
如果用户放大页面, 大多数浏览器会保持元素的宽度, 这会让文本变得难以阅读.
(Android WebKit 是一个特例, 会减小包含文本的元素的大小, 以适配屏幕. 这简直太妙了, 我认为其他浏览器也应该有这种操作.)
现在, 你可以试着设置 html{width: 320px}
. 及其内部的元素会缩小至 320px. 当用户使用的是一个几乎不包含任何内容的缩小页面, 所以需要用户放大页面才行.
为了解决这个问题,苹果发明了 meta 视口标签。当你设置<meta name="viewport" content="width=320">时,你就设置了布局视口的宽度为 320px。现在页面的初始状态也是合理的。
你可以给试图视口设置任意宽度, 包括 device-width. 后者指的是 screen.width(设备像素), 并且相应地重置视图视口.
不过这里有一个陷阱. 有时 screen.width 并没太大意义, 因为像素太高了. 比如, Nexus One 的宽度是 480px, 但谷歌工程师认为, 当使用 device-width 时, 给布局视口 480px 宽太高了. 他们把它缩小至 2/3, 因此 device-width 的宽度仍然是 320px, 像 iPhone 一样.
如果像传言的那样, 新版 iPhone 会支持更大像素(并不是一定是更大的屏幕!), 如果 iPhone 确实这样做了, 我并不感到惊讶.或许最终 device-width 还是 320px 呢.