两个 viewports 的故事-第二部分
原文链接: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 的故事-第二部分的更多相关文章
- 两个viewport的故事(第二部分)
原文:http://www.quirksmode.org/mobile/viewports2.html 在这个迷你系列的文章里边我将会解释viewport,以及许多重要元素的宽度是如何工作的,比如&l ...
- 两个viewport的故事(第一部分)
原文:http://www.quirksmode.org/mobile/viewports.html 在这个迷你系列的文章里边我将会解释viewport,以及许多重要元素的宽度是如何工作的,比如< ...
- 两个标签页定位第二个标签页元素时显示element not visible
问题描述 web页面有两个标签页, 当转换到第二个标签页定位元素时, 显示element not visible. 代码 ... //省略 WebElement ele= browser.getEle ...
- 可读性友好的JavaScript:两个专家的故事
每个人都想成为专家,但什么才是专家呢?这些年来,我见过两种被称为"专家"的人.专家一是指对语言中的每一个工具都了如指掌的人,而且无论是否有帮助,都一定要用好每一点.专家二也知道每一 ...
- JQuery给一个元素绑定两次点击事件(第二次点击事件)
由于项目的要求,需要给复选框设置样式,初始样式:,第一次点击的时候显示,第二次点击时候需要改变该样式:. 设计思路: 当点击次数为奇数时显示带有颜色的图片 当点击次数为偶数时显示没有颜色的图片 下边是 ...
- spring mvc 防止重复提交表单的两种方法,推荐第二种
第一种方法:判断session中保存的token 比较麻烦,每次在提交表单时都必须传入上次的token.而且当一个页面使用ajax时,多个表单提交就会有问题. 注解Token代码: package c ...
- <转>两个蛋蛋的故事
来自为知笔记(Wiz)
- html页面嵌套两个iframe页面导致第二个iframe页面高度失效的问题
1:这是因为最里面嵌套的iframe页面html和body高度无法设置问题,我的解决办法是js去控制iframe高度 2:js获取最子页面(content内容区域)的高度 var ifremHeigh ...
- easyui 解决连弹两个dialog时候,第二个dialog居中问题
$('#showDivSecond').dialog('center'); (该方法自1.3.1版开始可用)
随机推荐
- 使用 .NET WinForm 开发所见即所得的 IDE 开发环境,实现不写代码直接生成应用程序
直接切入正题,这是我09年到11年左右业余时间编写的项目,最初的想法很简单,做一个能拖拖拽拽就直接生成应用程序的工具,不用写代码,把能想到的业务操作全部封装起来,通过配置的方式把这些业务操作组织起来运 ...
- scanf()中清除输入缓冲区的几种方法归纳
应用场景:我们使用多个scanf()的时候,如果输入缓冲区还有数据的话,那么scanf()就不会询问用户输入,而是直接就将输入缓冲区的内容拿出来用了,这就导致了前面的错误影响到后面的内容,为了隔离这种 ...
- Linux下Nodejs安装(完整详细)
之前安装过windows下以及Mac下的node,感觉还是很方便的,不成想今天安装linux下的坑了老半天,特此记录. 首先去官网下载代码,这里一定要注意安装分两种,一种是Source Code源码, ...
- CRL快速开发框架系列教程三(更新数据)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- JQuery easyUI DataGrid 创建复杂列表头(译)
» Create column groups in DataGrid The easyui DataGrid has ability to group columns, as the followin ...
- 马里奥AI实现方式探索 ——神经网络+增强学习
[TOC] 马里奥AI实现方式探索 --神经网络+增强学习 儿时我们都曾有过一个经典游戏的体验,就是马里奥(顶蘑菇^v^),这次里约奥运会闭幕式,日本作为2020年东京奥运会的东道主,安倍最后也已经典 ...
- 【置顶】CoreCLR系列随笔
CoreCLR配置系列 在Windows上编译和调试CoreCLR GC探索系列 C++随笔:.NET CoreCLR之GC探索(1) C++随笔:.NET CoreCLR之GC探索(2) C++随笔 ...
- Git小技巧 - 指令别名及使用Beyond Compare作为差异比较工具
前言 本文主要写给使用命令行来操作Git的用户,用于提高Git使用的效率.至于使用命令还是GUI(Tortoise Git或VS的Git插件)就不在此讨论了,大家根据自己的的喜好选择就好.我个人是比较 ...
- Python学习
Python基础教程 网易云课堂-零基础入门学习Python
- Android中的多线程断点下载
首先来看一下多线程下载的原理.多线程下载就是将同一个网络上的原始文件根据线程个数分成均等份,然后每个单独的线程下载对应的一部分,然后再将下载好的文件按照原始文件的顺序"拼接"起来就 ...