原文链接:A tale of two viewports — part two

译者:nzbin

在这个迷你系列中,我将解释 viewports 和各种重要元素的宽度是如何工作的,比如说 <html> 元素,窗口以及屏幕。

我们将在本页讨论移动浏览器。如果你是刚刚接触移动端,我建议你首先阅读关于桌面浏览器的第一部分。这会让你在熟悉的环境中循序渐进。

移动浏览器的问题

手机浏览器与桌面浏览器的最大不同就是屏幕尺寸。对于一个基于桌面优化的网站,移动浏览器的显示效果明显不如桌面浏览器,要么缩小后文字太小无法阅读,要么放大后只能看到网站的一部分。

手机屏幕远小于桌面屏幕,最大宽度也就 400px 甚至更小(有些手机据称有更大的宽度,那是骗人的,或者至少给我们的是无用的信息)。

平板设备如 ipad 以及传闻基于 webOs 的惠普产品将缩小桌面与手机的差距,但也无法改变最基本的问题。因为网站也需要在移动端显示,所以我们必须让它们在小屏幕上正常显示。

最重要的问题与 CSS 有关,尤其视图的尺寸。如果我们一比一的复制桌面模型,CSS 可能不会正常工作。

将侧边栏设置为 width:10% 。如果移动浏览器和桌面浏览器的工作原理相同,侧边栏至多显示 40px 宽,确实太窄了。你的自适应布局看上去被压扁了。

解决这个问题的方法之一就是为移动浏览器设计特殊的网站。除了你是否应该这样做的问题之外,实际的问题是只有很少的网络公司会为移动单独设计网站。

手机浏览器的供应商希望为客户提供最好的用户体验,这意味着“尽可能如桌面显示的一样”。因此必须使用一些小花招。

两个viewports

所以视图太窄而不能作为你 CSS 布局的基础。很明显解决方式就是让视图更宽一点,我们要将视图分为两部分:视觉视图和布局视图。

George Cummins 在 Stack Overflow 上很好的解释了视图的基本概念,“把布局视图想象成一张无法改变大小和形状的很大的图片,你可以通过一个很小的相框来看这张图片。这个小相框的周围是不透明的材料,你只能看到相框内的图片。你从相框内看到的图片就是视觉视图。你可以拿着你的相框远离图片来看整张图片(缩小),或者离近一点只看图片的一部分(放大)。你也可以改变相框的角度,但是图片(视觉视图)的大小和尺寸不会变。”

 视觉视图是页面的一部分,如下所示。用户可以通过滚动来查看页面,或者通过缩放改变视觉视口的大小。

CSS 的布局是根据布局视图计算的,所以比视觉视图更宽。

由于 <html> 元素首先获取布局视图的尺寸,所以 CSS 被编译后页面就会比手机屏幕宽。这使得你的网站和在桌面浏览器中显示的一样。

布局视图有多宽呢?不同的浏览器各有差异。Safari/980px,Opera/850px,Android Webkit/800px,IE/974px。

还有一些浏览器比较特殊:。。。

缩放

很明显,两种视图都是用 CSS 像素测算。当视觉视图通过缩放改变时(如果是放大,屏幕上的 CSS 像素会变少),布局视图的尺寸不会变。(如果变化了,你的页面会用百分比的宽度被重新计算)

理解布局视图

为了理解布局视图的尺寸,我们应该看一下页面被完全缩小后发生了什么。大多数手机浏览器默认以完全缩小模式显示页面。

关键的一点是:布局视图在缩小模式下能够完全显示在屏幕上。(此时视觉视图等于布局视图)

如下图,布局视图的宽高与完全缩小模式下的宽高是相同的。当用户放大后,这些尺寸仍然相同。

布局视图的宽度始终相同。如果你旋转手机,视觉视图会发生改变,但是浏览器会放大布局视图来适应新的方向,所以布局视图和视觉视图的宽度仍然相等。

这会对布局视图的高度产生影响,纵向模式下布局视图的高度小于实际高度。但是网页开发者不关心高度,只关心宽度。

测算布局视图

现在我们想要测算两个视图的尺寸。由于浏览器之间的竞争我们有幸获得了一对属性值。

document.documentElement.clientWidth 和 -Height 包含了布局视图的尺寸。

旋转方向会影响高度,但不会影响宽度。

测算视觉视图

视觉视图通过 window.innerWidth/Height 测算。很明显,当用户放大或缩小时,由于更多或更少的 CSS 像素会适配屏幕,视觉视图尺寸会发生变化。

不幸的是这种方法并不兼容。很多浏览器仍然需要增加对视觉视图尺寸的支持。还没有浏览器具有其他保存该尺寸的属性值。所以我猜想 window.innerWidth/Height 是一个标准属性,尽管支持性不太好。

屏幕

和在桌面上一样, screen.width/height 能够得到屏幕的尺寸(设备像素)。作为开发者你可能不需要这些信息。你对屏幕的物理尺寸不感兴趣,而只关心当前屏幕上有多少 CSS 像素。

缩放比例

你无法直接获得缩放比例,但是可以通过 screen.width 和 window.innerWidth 的值求出来。当然只有两种属性都被支持时才有效。

幸运的是,缩放比例并不重要。你需要知道的是当前屏幕上有多少 CSS 像素,你可以通过 window.innerWidth 获得(如果该属性被支持的话)。

滚动偏移

你同样需要知道的是当前视觉视图相对于布局视图的位置。这就是滚动偏移,和桌面端一样,这个属性保存在 window.pageX/YOffset 中。

<html>元素

和在桌面上一样, document.documentElement.offsetWidth/Height 可以获得 <html> 元素在 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% 宽度。大多数浏览器会通过缩小来在屏幕上显示整个布局视图,如下图的效果

所有的用户会立即放大查看,但是大多数浏览器会保持元素的宽度不变,这使得文本很难阅读。

现在你可能会设置 html {width: 320px} 。html 元素收缩了,其他元素的宽度是 320px 的 100%。当用户放大的时候会看出来,而不是最初用户可能面对包含空白的缩小的页面。

为了解决这个问题,苹果公司发明了meta viewport 标签。当你设置 <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 会有更大的像素数(不一定需要更大的屏幕)。我可能不会对苹果效仿谷歌的行为感到吃惊。也许以后 device-width 就意味着 320px。

两个 viewports 的故事-第二部分的更多相关文章

  1. 两个viewport的故事(第二部分)

    原文:http://www.quirksmode.org/mobile/viewports2.html 在这个迷你系列的文章里边我将会解释viewport,以及许多重要元素的宽度是如何工作的,比如&l ...

  2. 两个viewport的故事(第一部分)

    原文:http://www.quirksmode.org/mobile/viewports.html 在这个迷你系列的文章里边我将会解释viewport,以及许多重要元素的宽度是如何工作的,比如< ...

  3. 两个标签页定位第二个标签页元素时显示element not visible

    问题描述 web页面有两个标签页, 当转换到第二个标签页定位元素时, 显示element not visible. 代码 ... //省略 WebElement ele= browser.getEle ...

  4. 可读性友好的JavaScript:两个专家的故事

    每个人都想成为专家,但什么才是专家呢?这些年来,我见过两种被称为"专家"的人.专家一是指对语言中的每一个工具都了如指掌的人,而且无论是否有帮助,都一定要用好每一点.专家二也知道每一 ...

  5. JQuery给一个元素绑定两次点击事件(第二次点击事件)

    由于项目的要求,需要给复选框设置样式,初始样式:,第一次点击的时候显示,第二次点击时候需要改变该样式:. 设计思路: 当点击次数为奇数时显示带有颜色的图片 当点击次数为偶数时显示没有颜色的图片 下边是 ...

  6. spring mvc 防止重复提交表单的两种方法,推荐第二种

    第一种方法:判断session中保存的token 比较麻烦,每次在提交表单时都必须传入上次的token.而且当一个页面使用ajax时,多个表单提交就会有问题. 注解Token代码: package c ...

  7. <转>两个蛋蛋的故事

    来自为知笔记(Wiz)

  8. html页面嵌套两个iframe页面导致第二个iframe页面高度失效的问题

    1:这是因为最里面嵌套的iframe页面html和body高度无法设置问题,我的解决办法是js去控制iframe高度 2:js获取最子页面(content内容区域)的高度 var ifremHeigh ...

  9. easyui 解决连弹两个dialog时候,第二个dialog居中问题

    $('#showDivSecond').dialog('center'); (该方法自1.3.1版开始可用)

随机推荐

  1. LINUX篇,设置MYSQL远程访问实用版

    每次设置root和远程访问都容易出现问题, 总结了个通用方法, 关键在于实用 step1: # mysql -u root mysql mysql> Grant all privileges o ...

  2. DDD CQRS架构和传统架构的优缺点比较

    明天就是大年三十了,今天在家有空,想集中整理一下CQRS架构的特点以及相比传统架构的优缺点分析.先提前祝大家猴年新春快乐.万事如意.身体健康! 最近几年,在DDD的领域,我们经常会看到CQRS架构的概 ...

  3. C# 中参数验证方式的演变

    一般在写方法的时候,第一步就是进行参数验证,这也体现了编码者的细心和缜密,但是在很多时候这个过程很枯燥和乏味,比如在拿到一个API设计文档的时候,通常会规定类型参数是否允许为空,如果是字符可能有长度限 ...

  4. 在Ubuntu 16.10 安装 git 并上传代码至 git.oschina.net

    1. 注册一个账号和创建项目 先在git.oschina.net上注册一个账号和新建一个project ,如project name 是"myTest". 2.安装git sudo ...

  5. spring注解源码分析--how does autowired works?

    1. 背景 注解可以减少代码的开发量,spring提供了丰富的注解功能.我们可能会被问到,spring的注解到底是什么触发的呢?今天以spring最常使用的一个注解autowired来跟踪代码,进行d ...

  6. 更愉快的书写CSS

    我在写CSS的时候经常会碰到些麻烦事儿: 1)看上去蛮简单的排版却写了很久 2)代码写的越来越散,总是这里补一句,那里补一句,没有条理性 3)margin.padding.font-size等属性在不 ...

  7. PHP代码优化

    1 代码优化 1 尽量静态化 如果一个方法能被静态,那就声明它为静态的,速度可提高1/4,甚至我测试的时候,这个提高了近三倍. 当然了,这个测试方法需要在十万级以上次执行,效果才明显. 其实静态方法和 ...

  8. autocomplete的使用

    autocomplete使用分为本地调用方法和读取远程读取数据源的方法 (1)本地调用方法 <script src="Scripts/jquery-1.4.1.min.js" ...

  9. OSGi规范的C#实现开源

    这是大约在3-4年前完成的一个C#实现的OSGi框架,实现的过程参照了OSGi规范与与一些实现思路(感谢当时的那些资料与项目),此框架虽然仅在几个小型项目有过实际的应用,但OSGi的规范实现还是相对比 ...

  10. BPM配置故事之案例11-操作外部数据源

    小明:可以获取ERP数据了-- 老李:哦,这么快?小伙子,我非常看好你,来来,别急着走,再陪我聊会-- 小明:--您老人家不是又要改流程吧? 老李:没有没有,哎嘿嘿嘿,我们这不都是为公司效率着想嘛,这 ...