原文:http://www.quirksmode.org/mobile/viewports.html
在这个迷你系列的文章里边我将会解释viewport,以及许多重要元素的宽度是如何工作的,比如元素,也包括窗口和屏幕。
这篇文章是关于桌面浏览器的,其唯一的目的就是为移动浏览器中相似的讨论做个铺垫。大部分开发者凭直觉已经明白了大部分桌面浏览器中的概念。在移动端我们将会接触到相同的概念,但是会更加复杂,所以对大家已经知道的术语做个提前的讨论将会对你理解移动浏览器产生巨大的帮助。
概念:设备像素和CSS像素你需要明白的第一个概念是CSS像素,以及它和设备像素的区别。
设备像素是我们直觉上觉得「靠谱」的像素。这些像素为你所使用的各种设备都提供了正规的分辨率,并且其值可以(通常情况下)从screen.width/height属性中读出。
如果你给一个元素设置了width: 128px的属性,并且你的显示器是1024px宽,当你最大化你的浏览器屏幕,这个元素将会在你的显示器上重复显示8次(大概是这样;我们先忽略那些微妙的地方)。
如果用户进行缩放,那么计算方式将会发生变化。如果用户放大到200%,那么你的那个拥有width: 128px属性的元素在1024px宽的显示器上只会重复显示4次。
现代浏览器中实现缩放的方式无怪乎都是「拉伸」像素。所以,元素的宽度并没有从128个像素被修改为256个像素;相反是实际像素被放大了两倍。形式上,元素仍然是128个CSS像素宽,即使它占据了256个设备像素的空间。
换句话说,放大到200%使一个CSS像素变成为一个设备像素的四倍。(宽度2倍,高度2倍,总共4倍)
一些配图可以解释清楚这个概念。这儿有四个100%缩放比的元素。这儿没有什么值得看的;CSS像素与设备像素完全重叠。
[attach]938[/attach]
现在让我们缩小。CSS像素开始收缩,这意味着现在一个设备像素覆盖了多个CSS像素。
[attach]939[/attach]
如果你进行放大,相反的行为会发生。CSS像素开始变大,现在一个CSS像素覆盖了多个设备像素。
[attach]940[/attach]
这儿的要点是你只对CSS像素感兴趣。这些就是那些控制你的样式表如何被渲染的像素。
设备像素对你(译者:指的是开发者)来说基本上没用。但是对于用户不一样;用户将会放大或者缩小页面直到他能舒服的阅读为止。无论怎样,缩放比例对你不会产生影响。浏览器将会自动的使你的CSS布局被拉伸或者被压缩。
100%缩放我是以假设缩放比例为100%来开始这个例子的。是时候需要更加严格的来定义一下这个100%了:
在缩放比例100%的情况下一个CSS像素完全等于一个设备像素。100%缩放的概念在接下来的解释中会非常有用,但是在你的日常工作中你不用过分的担心它。在桌面环境上你将会在100%缩放比例的情况下测试你的站点,但即使用户放大或者缩小,CSS像素的魔力将会保证你的布局保持相同的比率。
屏幕尺寸screen.width/height
让我们看一些实用的度量。我们将会以screen.width和screen.height做为开始。它们包括用户屏幕的整个宽度和高度。它们的尺寸是以设备像素来进行度量的,因为它们永远不会变:它们是显示器的属性,而不是浏览器的。
[attach]941[/attach]
Fun! 但是这些信息跟对我们有什么用呢?
基本上没用。用户的显示器尺寸对于我们来说不重要-好吧,除非你想度量它来丰富你的web统计数据库。
窗口尺寸window.innerWidth/Height
相反,你想知道的是浏览器窗口的内部尺寸。它告诉了你用户到底有多少空间可以用来做CSS布局。你可以通过window.innerWidth和window.innerHeight来获取这些尺寸。
[attach]942[/attach]
很显然,窗口的内部宽度是以CSS像素进行度量的。你需要知道你的布局空间中有多少可以挤进浏览器窗口,当用户放大的时候这个数值会减少。所以如果用户进行放大操作,那么在窗口中你能获取的空间将会变少,window.innerWidth/Height的值也变小了。 (这儿的例外是Opera,当用户放大的时候window.innerWidth/Height并没有减少:它们是以设备像素进行度量的。这个问题在桌面上是比较烦人的,但是就像我们将要看到的,这在移动设备上却是非常严重的。)
[attach]943[/attach]
注意度量的宽度和高度是包括滚动条的。它们也被视为内部窗口的一部分。(这大部分是因为历史原因造成的。)
滚动距离window.pageX/YOffset
window.pageXOffset和window.pageYOffset,包含了文档水平和垂直方向的滚动距离。所以你可以知道用户已经滚动了多少距离。
[attach]944[/attach]
这些属性也是以CSS像素进行度量的。你想知道的是文档已经被滚动了多长距离,不管它是放大还是缩小的状态。
理论上,如果用户向上滚动,然后放大,window.pageX/YOffset将会发生变化。但是,浏览器为了想保持web页面的连贯,会在用户缩放的时候保持相同的元素位于可见页面的顶部。这个机制并不能一直很完美的执行,但是它意味着在实际情况下window.pageX/YOffset并没有真正的更改:被滚动出窗口的CSS像素的数量仍然(大概)是相同的。
[attach]945[/attach]
概念:viewport在我们继续介绍更多的JavaScript属性之前,我们必须介绍另一个概念:viewport。
viewport的功能是用来约束你网站中最顶级包含块元素(containing block)的。
这听起来有一点模糊,所以看一个实际的例子。假设你有一个流式布局,并且你众多边栏中的一个具有width: 10%属性。现在这个边栏会随着浏览器窗口大小的调整而恰好的放大和收缩。但是这到底是如何工作的呢?
从技术上来说,发生的事情是边栏获取了它父元素宽度的10%。比方说是元素(并且你还没有给它设置过宽度)。所以问题就变成了的宽度是哪个?
普通情况下,所有块级元素使用它们父元素宽度的100%(这儿有一些例外,但是让我们现在先忽略它)。所以元素和它的父元素一样宽。
那么元素的宽度是多少?它的宽度和浏览器窗口宽度一样。这就是为什么你的那个拥有width: 10%属性的侧边栏会占据整个浏览器窗口的10%。所有web开发者都很直观的知道并且在使用它。
你可能不知道的是这个行为在理论上是如何工作的。理论上,元素的宽度是被viewport的宽度所限制的。元素使用viewport宽度的100%。
viewport,接着,实际上等于浏览器窗口:它就是那么定义的。viewport不是一个HTML结构,所以你不能用CSS来改变它。它在桌面环境下只是拥有浏览器窗口的宽度和高度。在移动环境下它会有一些复杂。
后果 Consequences这个状况会有产生一些异样的后果。你可以在这个站点看到这些后果中的一个。滚动到顶部,然后放大两次或者三次,之后这个站点的内容就从浏览器窗口溢出了。
现在滚动到右边,然后你将会看见站点顶部的蓝色边栏不再覆盖一整行了。
[attach]946[/attach]
这个行为是由于viewport的定义方式而产生的一个后果。我之前给顶部的蓝色边栏设置了width: 100%。什么的100%?元素的100%,它的宽度和viewport是一样的,viewport的宽度是和浏览器窗口一样的。
问题是:在100%缩放的情况下这个工作的很好,现在我们进行了放大操作,viewport变得比我的站点的总体宽度要小。这对于viewport它本身来说没什么影响,内容现在从元素中溢出了,但是那个元素拥有overflow: visible,这意味着溢出的内容在任何情况下都将会被显示出来。
但是蓝色边栏并没有溢出。我之前给它设置了width: 100%,并且浏览器把viewport的宽度赋给了它。它们根本就不在乎现在宽度实在是太窄了。
[attach]947[/attach]
文档宽度?我真正需要知道的是页面中全部内容的宽度是多少,包括那些「伸出」的部分。据我所知得到这个值是不可能的(好吧,除非你去计算页面上所有元素的宽度和边距,但是委婉的说,这是容易出错的)。
我开始相信我们需要一个我称其为「文档宽度」(document width,很显然用CSS像素进行度量)的JavaScript属性对。
[attach]948[/attach]
并且如果我们真的如此时髦,为什么不把这个值引入到CSS中?我将会给我的蓝色边栏设置width: 100%,此值基于文档宽度,而不是元素的宽度。(但是这个很复杂,并且如果不能实现我也不会感到惊讶。)
浏览器厂商们,你们怎么认为的?
度量viewportdocument.documentElement.clientWidth/Height
你可能想知道viewport的尺寸。它们可以通过document.documentElement.clientWidth和-Height得到。
[attach]949[/attach]
如果你了解DOM,你应该知道document.documentElement实际上指的是元素:即任何HTML文档的根元素。可以说,viewport要比它更高一层;它是包含元素的元素。如果你给元素设置width属性,那么这将会产生影响。(我不推荐这么做,但是那是可行的。)
在那种情况下document.documentElement.clientWidth和-Height给出的仍然是viewport的尺寸,而不是元素的。(这是一个特殊的规则,只对这个元素的这个属性对产生作用。在任何其他的情况下,使用的是元素的实际宽度。)
[attach]950[/attach]
所以document.documentElement.clientWidth和-Height一直代表的是viewport的尺寸,不管元素的尺寸是多少。
两个属性对但是难道viewport宽度的尺寸也可以通过window.innerWidth/Height来提供吗?怎么说呢,模棱两可。
两个属性对之间存在着正式区别:document.documentElement.clientWidth和-Height并不包含滚动条,但是window.innerWidth/Height包含。这像是鸡蛋里挑骨头。
事实上两个属性对的存在是浏览器战争的产物。当时Netscape只支持window.innerWidth/Height,IE只支持document.documentElement.clientWidth和Height。从那时起所有其他浏览器开始支持clientWidth/Height,但是IE没有支持window.innerWidth/Height。
在桌面环境上拥有两个属性对是有一些累赘的 - 但是就像我们将要看到的,在移动端这将会得到祝福。
度量元素document.documentElement.offsetWidth/Height
所以clientWidth/Height在所有情况下都提供viewport的尺寸。但是我们去哪里获取元素本身的尺寸呢?它们存储在document.documentElement.offsetWidth和-Height之中。
[attach]951[/attach]
这些属性可以使你以块级元素的形式访问元素;如果你设置width,那么offsetWidth将会表示它。
[attach]952[/attach]
事件中的坐标pageX/Y, clientX/Y, screenX/Y
然后是事件中的坐标。当一个鼠标事件发生时,有不少于五种属性对可以给你提供关于事件位置的信息。对于我们当前的讨论来说它们当中的三种是重要的:
[attach]953[/attach]
[attach]954[/attach]
[attach]955[/attach]
90%的时间你将会使用pageX/Y;通常情况下你想知道的是相对于文档的事件坐标。其他的10%时间你将会使用clientX/Y。你永远不需要知道事件相对于屏幕的坐标。
媒体查询媒体查询
最后,说说关于媒体查询的事。原理很简单:你可以声明「只在页面宽度大于,等于或者小于一个特定尺寸的时候才会被执行」的特殊的CSS规则。比如:
div.sidebar { width: 300px;}@media all and (max-width: 400px) { // styles assigned when width is smaller than 400px; div.sidebar { width: 100px; }}当前sidebar是300px宽,除了当宽度小于400px的时候,在那种情况下sidebar变得100px宽。
问题很显然:我们这儿度量的是哪个宽度?
这儿有两个对应的媒体查询:width/height和device-width/device-height。
[attach]956[/attach]
你应该使用哪个?这还用想?当然是width。Web开发者对设备宽度不感兴趣;这个是浏览器窗口的宽度。
所以在桌面环境下去使用width而去忘记device-width吧。我们即将看到这个情况在移动端会更加麻烦。
总结本文总结了我们对桌面浏览器行为的探寻。这个系列的第二部分把这些概念指向了移动端,并显示的指出了与桌面环境上的一些重要区别。
原文:http://www.quirksmode.org/mobile/viewports2.html
在这个迷你系列的文章里边我将会解释viewport,以及许多重要元素的宽度是如何工作的,比如元素,也包括窗口和屏幕。
这篇文章我们来聊聊关于移动浏览器的内容。如果你对移动开发完全是一个新手的话,我建议你先读一下第一篇关于桌面浏览器的文章,先在熟悉的环境中进行下热身。
移动浏览器的问题当我们比较移动浏览器和桌面浏览器的时候,它们最显而易见的不同就是屏幕尺寸。为桌面浏览器所设计的网站在移动浏览器中显示的内容明显要少于在桌面浏览器中显示的;不管是对其进行缩放直到文字小得无法阅读,还是在屏幕中以合适的尺寸只显示站点中的一小部分内容。
移动设备的屏幕比桌面屏幕要小得多;想想其最大有400px宽,有时候会小很多。(一些手机声称拥有更大的宽度,但是它在撒谎-或者也可以说它给我们提供了没用的信息。)
平板设备中的像素中间层会在桌面环境和移动环境的缺口之间架起一段桥梁,比如像iPad或者传说中HP基于webOS所研发的设备,但是这并没有改变根本问题。站点必须也能在移动设备上工作,所以我们不得不让它们能在小尺寸的屏幕上正常显示。
最重要的问题在CSS上,特别是viewport的尺寸。如果我们照搬桌面环境的模式,那么我们的CSS就要立马熄火了(译者:即显示混乱)。
让我们看下之前sidebar为width: 10%的例子。如果移动浏览器想要实现跟桌面浏览器一样的行为,它们最多为元素设置40px的宽度,但是这太窄了。你的流式布局会看起来被挤乱了。
解决这个问题的一个方法是为移动浏览器建立一个特定的站点。先抛开你是否有必要这么做这个基本问题,而实际的情况是只有很少的网站拥有者真正知道要对移动设备做特殊的处理。
移动浏览器厂商想给它们的客户尽可能的提供最好的体验,这现在指的就是「尽可能的跟桌面一样」。因此耍一些花招是必要的。
两个viewportviewport太窄了,以至于不能正常展示你的CSS布局。明显的解决方案是使viewport变宽一些。无论如何,需要把它分成两部分:visual viewport和layout viewport。
George Cummins在Stack Overflow上对基本概念给出了最佳解释:
把layout viewport想像成为一张不会变更大小或者形状的大图。现在想像你有一个小一些的框架,你通过它来看这张大图。(译者:可以理解为「管中窥豹」)这个小框架的周围被不透明的材料所环绕,这掩盖了你所有的视线,只留这张大图的一部分给你。你通过这个框架所能看到的大图的部分就是visual viewport。当你保持框架(缩小)来看整个图片的时候,你可以不用管大图,或者你可以靠近一些(放大)只看局部。你也可以改变框架的方向,但是大图(layout viewport)的大小和形状永远不会变。
也看一下Chris给出的解释。
visual viewport是页面当前显示在屏幕上的部分。用户可以通过滚动来改变他所看到的页面的部分,或者通过缩放来改变visual viewport的大小。
[attach]957[/attach]
无论怎样,CSS布局,尤其是百分比宽度,是以layout viewport做为参照系来计算的,它被认为要比visual viewport宽。
所以元素在初始情况下用的是layout viewport的宽度,并且你的CSS是在屏幕(译者注:宽度等于layout viewport的虚拟屏幕)好像明显比电话屏幕宽(物理屏幕)要宽的假设基础上进行解释的。这使得你站点布局的行为与其在桌面浏览器上的一样。
layout viewport有多宽?每个浏览器都不一样。Safari iPhone为980px,Opera为850px,Android WebKit为800px,最后IE为974px。
一些浏览器有特殊的行为:
很显然两个viewport都是以CSS像素度量的。但是当进行缩放(如果你放大,屏幕上的CSS像素会变少)的时候,visual viewport的尺寸会发生变化,layout viewport的尺寸仍然跟之前的一样。(如果不这样,你的页面将会像百分比宽度被重新计算一样而经常被重新布局。)
理解layout viewport为了理解layout viewport的尺寸,我们不得不看一下当页面被完全缩小后会发生什么。许多移动浏览器会在初始情况下以完全缩小的模式来展示任何页面。
重点是:浏览器已经为自己的layout viewport选择了尺寸,这样的话它在完全缩小模式的情况下完整的覆盖了屏幕(并且等于visual viewport)。
[attach]958[/attach]
所以layout viewport的宽度和高度等于在最大限度缩小的模式下屏幕上所能显示的任何内容的尺寸。当用户放大的时候这些尺寸保持不变。
[attach]959[/attach]
layout viewport宽度一直是一样的。如果你旋转你的手机,visual viewport会发生变化,但是浏览器通过轻微的放大来适配这个新的朝向,所以layout viewport又和visual viewport一样宽了。
[attach]960[/attach]
这对layout viewport的高度会有影响,现在的高度比肖像模式(竖屏)要小。但是web开发者不在乎高度,只在乎宽度。
[attach]961[/attach]
度量layout viewport我们现在有两个需要度量的viewport。很幸运的是浏览器战争给我们提供了两个属性对。
document.documentElement.clientWidth和-Height包含了layout viewport的尺寸。
document.documentElement.clientWidth/Height
[attach]962[/attach]
朝向会对高度产生影响,但对宽度不会产生影响。
[attach]963[/attach]
度量visual viewport对于visual viewport,它是通过window.innerWidth/Height来进行度量的。很明显当用户缩小或者放大的时候,度量的尺寸会发生变化,因为屏幕上的CSS像素会增加或者减少。
window.innerWidth/Height
[attach]964[/attach]
不幸的是这是浏览器不兼容问题中的一部分;许多浏览器仍然不得不增加对visual viewport度量尺寸的支持。但是没有浏览器把这个度量尺寸存放任何其他的属性对中,所以我猜window.innerWidth/Height是标准,尽管它被支持的很糟。
屏幕像桌面环境一样,screen.width/height提供了以设备像素为单位的屏幕尺寸。像在桌面环境上一样,做为一个开发者你永远不需要这个信息。你对屏幕的物理尺寸不感兴趣,而是对屏幕上当前有多少CSS像素感兴趣。
screen.width and screen.height
[attach]965[/attach]
缩放比例 zoom level直接读出缩放比例是不可能的,但是你可以通过以screen.width除以window.innerWidth来获取它的值。当然这只有在两个属性都被完美支持的情况下才有用。
幸运的是缩放比例并不太重要。你需要知道的是当前屏幕上有多少个CSS像素。你可以通过window.innerWidth来获取这个信息,如果它被正确支持的话。
滚动距离Scrolling offset你还需知道的是visual viewport当前相对于layout viewport的位置。这是滚动距离,并且就像在桌面一样,它被存储在window.pageX/YOffset之中。
window.pageX/YOffset
[attach]966[/attach]
元素就像在桌面上一样,document.documentElement.offsetWidth/Height提供了以CSS像素为单位的元素的整个尺寸。
document.documentElement.offsetWidth/Height
[attach]967[/attach]
媒体查询Media queries媒体查询和其在桌面环境上的工作方式一样。width/height使用layout viewport做为参照物,并且以CSS像素进行度量,device-width/height使用设备屏幕,并且以设备像素进行度量。
换句话说,width/height是document.documentElement.clientWidth/Height值的镜像,同时device-width/height是screen.width/height值的镜像。(它们在所有浏览器中实际上就是这么做的,即使这个镜像的值不正确。)
媒体查询
[attach]968[/attach]
现在哪个度量的尺寸对web开发者更有用?我的观点是,不知道。
我开始认为device-width是最重要的那一个,因为它给我们提供了关于我们可能会使用的设备的一些信息。比如,你可以根据设备的宽度来更改你的布局的宽度。不过,你也可以使用来做这件事情;使用device-width媒体查询并不是绝对必要的。
那么width究竟是不是更重要的媒体查询呢?可能是;它提供了某些线索,这些线索是关于浏览器厂商认为在这个设备上网站应该有的正确宽度。但是这有些模糊不清,并且width媒体查询实际上不提供任何其他信息。
所以我不做选择。目前我认为媒体查询在分辨你是否在使用桌面电脑,平板,或者移动设备方面很重要,但是对于区分各种平板或者移动设备并没有什么用。
或者还有其他用处。
事件坐标这里的事件坐标与其在桌面环境上的工作方式差不多。不幸的是,在十二个测试过的浏览器中只有Symbian WebKit和Iris这两个浏览器能获取到三个完全正确的值。其他所有浏览器都或多或少有些严重的问题。
pageX/Y仍然是相对于页面,以CSS像素为单位,并且它是目前为止三个属性对中最有用的,就像它在桌面环境上的那样。
Event coordinates
[attach]969[/attach]
clientX/Y是相对于visual viewport来计算,以CSS像素为单位的。这有道理的,即使我还不能完全指出这么做的好处。
screenX/Y是相对于屏幕来计算,以设备像素为单位。当然,这和clientX/Y用的参照系是一样的,并且设备像素在这没有用处。所以我们不需要担心screenX/Y;跟在桌面环境上一样没有用处。
[attach]970[/attach]
viewport meta标签Meta viewport
最后,让我们讨论一下;起初它是苹果做的一个扩展,但是与此同时被更多的浏览器所借鉴。它的意思是调整layout viewport的大小。为了理解为什么这么做是必要的,让我们后退一步。
假设你创建了一个简单的页面,并且没有给你的元素设置「宽度」。那么现在它们会被拉伸来填满layout viewport宽度的100%。大部分浏览器会进行缩放从而在屏幕上展示整个layout viewport,产生下面这样的效果:
[attach]971[/attach]
所有用户将会立刻进行放大操作,这个是工作的,但是大部分浏览器完好无缺的保持元素的宽度,这使得文字很难阅读。
[attach]972[/attach]
(值得注意的例外是Android WebKit,它实际上会减小包含文字的元素的大小,所以文字就能适配屏幕。这简直太有才了,我觉得所有其他浏览器应该借鉴这个行为。我过阵子将会完整的写一下这个议题。)
现在你应该尝试设置html {width: 320px}。现在元素收缩了,并且其他元素现在使用的是320px的100%。这在用户进行放大操作的时候有用,但是在初始状态是没用的,当用户面对一个缩小了的页面这几乎不包含任何内容。
[attach]973[/attach]
为了绕开这个问题苹果发明了viewport meta标签。当你设置的时候,你就设置了layout viewport的宽度为320px。现在页面的初始状态也是正确的。
你可以把layout viewport的宽度设置为任何你想要的尺寸,包括device-width。device-width会把screen.width(以设备像素为单位)做为其值,并相应的重置layout viewport的尺寸。
但这里有一个隐情。有时候正规的screen.width不那么明了,因为像素的数量太大了。比如,Nexus One的正规宽度是480px,但是Google的工程师们觉得当使用device-width的时候,layout viewport的宽度为480px,这有些太大了。他们把宽度缩小为三分之二,所以device-width会返回给你一个320px的宽度,就像在iPhone上一样。
如果,像传闻那样,新的iPhone将会炫耀一个更大的像素数量(并不意味着一个更大的屏幕),如果苹果借鉴了这个行为我将不会感到惊讶。也许最终device-width就意味着320px。
相关研究一些相关的主题不得不需要进行更深一步的研究:
欢迎光临 源于生活 (http://bbs.vingoo.info/) | Powered by Discuz! X3.1 |