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

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

相关推荐
小曲曲27 分钟前
接口上传视频和oss直传视频到阿里云组件
javascript·阿里云·音视频
学不会•2 小时前
css数据不固定情况下,循环加不同背景颜色
前端·javascript·html
EasyNTS3 小时前
H.264/H.265播放器EasyPlayer.js视频流媒体播放器关于websocket1006的异常断连
javascript·h.265·h.264
活宝小娜4 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点4 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow4 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o4 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
开心工作室_kaic5 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
刚刚好ā5 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
沉默璇年6 小时前
react中useMemo的使用场景
前端·react.js·前端框架