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

原文:http://www.quirksmode.org/mobile/viewports.htmlcss

在这个迷你系列的文章里边我将会解释viewport,以及许多重要元素的宽度是如何工做的,好比<html>元素,也包括窗口和屏幕。html

这篇文章是关于桌面浏览器的,其惟一的目的就是为移动浏览器中类似的讨论作个铺垫。大部分开发者凭直觉已经明白了大部分桌面浏览器中的概念。在移动端咱们将会接触到相同的概念,可是会更加复杂,因此对你们已经知道的术语作个提早的讨论将会对你理解移动浏览器产生巨大的帮助。web

概念:设备像素和CSS像素

你须要明白的第一个概念是CSS像素,以及它和设备像素的区别。数据库

设备像素是咱们直觉上以为「靠谱」的像素。这些像素为你所使用的各类设备都提供了正规的分辨率,而且其值能够(一般状况下)从screen.width/height属性中读出。浏览器

若是你给一个元素设置了width: 128px的属性,而且你的显示器是1024px宽,当你最大化你的浏览器屏幕,这个元素将会在你的显示器上重复显示8次(大概是这样;咱们先忽略那些微妙的地方)。ide

若是用户进行缩放,那么计算方式将会发生变化。若是用户放大到200%,那么你的那个拥有width: 128px属性的元素在1024px宽的显示器上只会重复显示4次。布局

现代浏览器中实现缩放的方式无怪乎都是「拉伸」像素。因此,元素的宽度并无从128个像素被修改成256个像素;相反是实际像素被放大了两倍。形式上,元素仍然是128个CSS像素宽,即便它占据了256个设备像素的空间。测试

换句话说,放大到200%使一个CSS像素变成为一个设备像素的四倍。(宽度2倍,高度2倍,总共4倍)网站

一些配图能够解释清楚这个概念。这儿有四个100%缩放比的元素。这儿没有什么值得看的;CSS像素与设备像素彻底重叠。ui

csspixels_100

如今让咱们缩小。CSS像素开始收缩,这意味着如今一个设备像素覆盖了多个CSS像素。

csspixels_out

若是你进行放大,相反的行为会发生。CSS像素开始变大,如今一个CSS像素覆盖了多个设备像素。

csspixels_in

这儿的要点是你只对CSS像素感兴趣。这些就是那些控制你的样式表如何被渲染的像素。

设备像素对你(译者:指的是开发者)来讲基本上没用。可是对于用户不同;用户将会放大或者缩小页面直到他能舒服的阅读为止。不管怎样,缩放比例对你不会产生影响。浏览器将会自动的使你的CSS布局被拉伸或者被压缩。

100%缩放

我是以假设缩放比例为100%来开始这个例子的。是时候须要更加严格的来定义一下这个100%了:

在缩放比例100%的状况下一个CSS像素彻底等于一个设备像素。

100%缩放的概念在接下来的解释中会很是有用,可是在你的平常工做中你不用过度的担忧它。在桌面环境上你将会在100%缩放比例的状况下测试你的站点,但即便用户放大或者缩小,CSS像素的魔力将会保证你的布局保持相同的比率。

屏幕尺寸

screen.width/height

  • 意义:用户屏幕的总体大小。
  • 度量单位:设备像素。
  • 浏览器错误:IE8以CSS像素对其进行度量,IE7和IE8模式下都有这个问题。

让咱们看一些实用的度量。咱们将会以screen.widthscreen.height作为开始。它们包括用户屏幕的整个宽度和高度。它们的尺寸是以设备像素来进行度量的,由于它们永远不会变:它们是显示器的属性,而不是浏览器的。

desktop_screen

Fun! 可是这些信息跟对咱们有什么用呢?

基本上没用。用户的显示器尺寸对于咱们来讲不重要-好吧,除非你想度量它来丰富你的web统计数据库。

窗口尺寸

window.innerWidth/Height

  • 意义:浏览器窗口的总体大小,包括滚动条。
  • 度量单位:CSS像素。
  • 浏览器错误:IE7不支持。Opera以设备像素进行度量。

相反,你想知道的是浏览器窗口的内部尺寸。它告诉了你用户到底有多少空间能够用来作CSS布局。你能够经过window.innerWidthwindow.innerHeight来获取这些尺寸。

desktop_inner

很显然,窗口的内部宽度是以CSS像素进行度量的。你须要知道你的布局空间中有多少能够挤进浏览器窗口,当用户放大的时候这个数值会减小。因此若是用户进行放大操做,那么在窗口中你能获取的空间将会变少,window.innerWidth/Height的值也变小了。 (这儿的例外是Opera,当用户放大的时候window.innerWidth/Height并无减小:它们是以设备像素进行度量的。这个问题在桌面上是比较烦人的,可是就像咱们将要看到的,这在移动设备上倒是很是严重的。)

desktop_inner_zoomed

注意度量的宽度和高度是包括滚动条的。它们也被视为内部窗口的一部分。(这大部分是由于历史缘由形成的。)

滚动距离

window.pageX/YOffset

  • 意义:页面滚动的距离。
  • 度量单位:CSS像素。
  • 浏览器错误:无。

window.pageXOffsetwindow.pageYOffset,包含了文档水平和垂直方向的滚动距离。因此你能够知道用户已经滚动了多少距离。

desktop_page

这些属性也是以CSS像素进行度量的。你想知道的是文档已经被滚动了多长距离,无论它是放大仍是缩小的状态。

理论上,若是用户向上滚动,而后放大,window.pageX/YOffset将会发生变化。可是,浏览器为了想保持web页面的连贯,会在用户缩放的时候保持相同的元素位于可见页面的顶部。这个机制并不能一直很完美的执行,可是它意味着在实际状况下window.pageX/YOffset并无真正的更改:被滚动出窗口的CSS像素的数量仍然(大概)是相同的。

desktop_page_zoomed

概念:viewport

在咱们继续介绍更多的JavaScript属性以前,咱们必须介绍另外一个概念:viewport。

viewport的功能是用来约束你网站中最顶级包含块元素(containing block)<html>的。

这听起来有一点模糊,因此看一个实际的例子。假设你有一个流式布局,而且你众多边栏中的一个具备width: 10%属性。如今这个边栏会随着浏览器窗口大小的调整而刚好的放大和收缩。可是这究竟是如何工做的呢?

从技术上来讲,发生的事情是边栏获取了它父元素宽度的10%。比方说是<body>元素(而且你尚未给它设置过宽度)。因此问题就变成了<body>的宽度是哪一个?

普通状况下,全部块级元素使用它们父元素宽度的100%(这儿有一些例外,可是让咱们如今先忽略它)。因此<body>元素和它的父元素<html>同样宽。

那么<html>元素的宽度是多少?它的宽度和浏览器窗口宽度同样。这就是为何你的那个拥有width: 10%属性的侧边栏会占据整个浏览器窗口的10%。全部web开发者都很直观的知道而且在使用它。

你可能不知道的是这个行为在理论上是如何工做的。理论上,<html>元素的宽度是被viewport的宽度所限制的。<html>元素使用viewport宽度的100%。

viewport,接着,实际上等于浏览器窗口:它就是那么定义的。viewport不是一个HTML结构,因此你不能用CSS来改变它。它在桌面环境下只是拥有浏览器窗口的宽度和高度。在移动环境下它会有一些复杂。

后果 Consequences

这个情况会有产生一些异样的后果。你能够在这个站点看到这些后果中的一个。滚动到顶部,而后放大两次或者三次,以后这个站点的内容就从浏览器窗口溢出了。

如今滚动到右边,而后你将会看见站点顶部的蓝色边栏再也不覆盖一整行了。

desktop_htmlbehaviour

这个行为是因为viewport的定义方式而产生的一个后果。我以前给顶部的蓝色边栏设置了width: 100%。什么的100%?<html>元素的100%,它的宽度和viewport是同样的,viewport的宽度是和浏览器窗口同样的。

问题是:在100%缩放的状况下这个工做的很好,如今咱们进行了放大操做,viewport变得比个人站点的整体宽度要小。这对于viewport它自己来讲没什么影响,内容如今从<html>元素中溢出了,可是那个元素拥有overflow: visible,这意味着溢出的内容在任何状况下都将会被显示出来。

可是蓝色边栏并无溢出。我以前给它设置了width: 100%,而且浏览器把viewport的宽度赋给了它。它们根本就不在意如今宽度实在是太窄了。

desktop_100percent

文档宽度?

我真正须要知道的是页面中所有内容的宽度是多少,包括那些「伸出」的部分。据我所知获得这个值是不可能的(好吧,除非你去计算页面上全部元素的宽度和边距,可是委婉的说,这是容易出错的)。

我开始相信咱们须要一个我称其为「文档宽度」(document width,很显然用CSS像素进行度量)的JavaScript属性对。

desktop_documentwidth

而且若是咱们真的如此时髦,为何不把这个值引入到CSS中?我将会给个人蓝色边栏设置width: 100%,此值基于文档宽度,而不是<html>元素的宽度。(可是这个很复杂,而且若是不能实现我也不会感到惊讶。)

浏览器厂商们,大家怎么认为的?

度量viewport

document.documentElement.clientWidth/Height

  • 意义:Viewport尺寸。
  • 度量单位:CSS像素。
  • 浏览器错误:无。

你可能想知道viewport的尺寸。它们能够经过document.documentElement.clientWidth-Height获得。

desktop_client

若是你了解DOM,你应该知道document.documentElement实际上指的是<html>元素:即任何HTML文档的根元素。能够说,viewport要比它更高一层;它是包含<html>元素的元素。若是你给<html>元素设置width属性,那么这将会产生影响。(我不推荐这么作,可是那是可行的。)

在那种状况下document.documentElement.clientWidth-Height给出的仍然是viewport的尺寸,而不是<html>元素的。(这是一个特殊的规则,只对这个元素的这个属性对产生做用。在任何其余的状况下,使用的是元素的实际宽度。)

desktop_client_smallpage

因此document.documentElement.clientWidth-Height一直表明的是viewport的尺寸,无论<html>元素的尺寸是多少。

两个属性对

可是难道viewport宽度的尺寸也能够经过window.innerWidth/Height来提供吗?怎么说呢,模棱两可。

两个属性对之间存在着正式区别:document.documentElement.clientWidth-Height并不包含滚动条,可是window.innerWidth/Height包含。这像是鸡蛋里挑骨头。

事实上两个属性对的存在是浏览器战争的产物。当时Netscape只支持window.innerWidth/Height,IE只支持document.documentElement.clientWidthHeight。从那时起全部其余浏览器开始支持clientWidth/Height,可是IE没有支持window.innerWidth/Height

在桌面环境上拥有两个属性对是有一些累赘的 - 可是就像咱们将要看到的,在移动端这将会获得祝福。

度量\<html>元素

document.documentElement.offsetWidth/Height

  • 意义:元素(也就是页面)的尺寸。
  • 度量单位:CSS像素。
  • 浏览器错误:IE度量的是viewport,而不是元素。

因此clientWidth/Height在全部状况下都提供viewport的尺寸。可是咱们去哪里获取<html>元素自己的尺寸呢?它们存储在document.documentElement.offsetWidth-Height之中。

desktop_offset

这些属性可使你以块级元素的形式访问<html>元素;若是你设置width,那么offsetWidth将会表示它。

desktop_offset_smallpage

事件中的坐标

pageX/Y, clientX/Y, screenX/Y

  • 意义:见正文。
  • 度量单位:见正文。
  • 浏览器错误:IE不支持pageX/Y。IE和Opera以CSS像素为单位计算screenX/Y。

而后是事件中的坐标。当一个鼠标事件发生时,有很多于五种属性对能够给你提供关于事件位置的信息。对于咱们当前的讨论来讲它们当中的三种是重要的:

  • pageX/Y提供了相对于<html>元素的以CSS像素度量的坐标。

desktop_pageXY

  • clientX/Y提供了相对于viewport的以CSS像素度量的坐标。

desktop_clientXY

  • screenX/Y提供了相对于屏幕的以设备像素进行度量的坐标。

desktop_screenXY

90%的时间你将会使用pageX/Y;一般状况下你想知道的是相对于文档的事件坐标。其余的10%时间你将会使用clientX/Y。你永远不须要知道事件相对于屏幕的坐标。

媒体查询

媒体查询

  • 意义:见正文。
  • 度量单位:见正文。
  • 浏览器错误:IE不支持它们。
    • 若是 device-width/height是以CSS像素进行度量的,那么Firefox将会使用screen.width/height的值。
    • 若是width/height是以设备像素进行度量的,那么Safari和Chrome将会使用documentElement.clientWidth/Height的值。

最后,说说关于媒体查询的事。原理很简单:你能够声明「只在页面宽度大于,等于或者小于一个特定尺寸的时候才会被执行」的特殊的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/heightdevice-width/device-height

  1. width/height使用和documentElement .clientWidth/Height(换句话说就是viewport宽高)同样的值。它是工做在CSS像素下的。

  2. device-width/device-height使用和screen.width/height(换句话说就是屏幕的宽高)同样的值。它工做在设备像素下面。

desktop_mediaqueries

你应该使用哪一个?这还用想?固然是width。Web开发者对设备宽度不感兴趣;这个是浏览器窗口的宽度。

因此在桌面环境下去使用width而去忘记device-width吧。咱们即将看到这个状况在移动端会更加麻烦。

总结

本文总结了咱们对桌面浏览器行为的探寻。这个系列的第二部分把这些概念指向了移动端,并显示的指出了与桌面环境上的一些重要区别。

相关文章
相关标签/搜索