likes
comments
collection
share

[译] 两种视口的故事(二)

作者站长头像
站长
· 阅读数 10

原作者: 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。

一些浏览器比较特殊:

1. Symbian WebKit 试图保持布局视窗等于视觉视窗,这意味着具有百分比宽度的元素可能会表现得很奇怪。但是,如果页面由于绝对宽度而无法放入视觉视口,则浏览器将布局视口拉伸到最大 850px。

2. 三星 WebKit(在 bada 上)使布局视口与最宽元素一样宽。

3. 在黑莓上,布局视窗等于 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 呢.