写在前面:读到一篇关于viewPort的文章,觉得写得很好,就根据自己理解翻译成中文供参考。我翻译的有问题的话还请大家多多指正。原文地址:A tale of two viewports — part one (quirksmode.org)
目录
测量viewPort(Measuring the viewport)
测量<html>元素(measuring the <html> element)
在这个系列,我们将探索viewports和各种重要元素是如何工作的,例如,<html>元素,window和screen。
设备像素和CSS像素
首先需要理解CSS像素和设备像素的区别。
设备像素就是我们直观上认为的设备屏幕的大小尺寸,可以通过screen.width/height来测量出。
给定一个<html>元素宽度为128px,显示屏的宽度为1024px,然后将浏览器的窗口最大化,那么8个这样得元素就可以并排横向布满浏览器的屏幕。
如果用户继续放大浏览器,计算方式将会改变。如果用户将浏览器缩放到200%,那么4个宽度为128px的元素将会并排横向覆盖宽度为1024px的屏目。
缩放在现代浏览器中只不过是拉伸像素而已。元素的宽度并没有从128像素变到256像素。而实际像素是原来的2倍。尽管它占据了256设备像素,正常来说,这个元素的宽度依然是128 CSS像素。
换句话说,缩放到200%是让一个CSS像素增大到一个设备像素的4倍(2倍的宽度,2倍的高度,总共是4倍)
用下面的图片可以更清楚的进行说明。
这是4像素在浏览器窗口100%的缩放水平下,CSS像素完全重叠在设备像素上。
现在将浏览器窗口进行缩小,CSS像素开始缩小,意味着现在一个设备像素与几个CSS像素重叠。如下图所示:
如果再次放大,则相反,CSS像素开始增长,现在一个CSS像素重叠几个设备像素。如下图所示:
这儿关键是我们只关心CSS像素。正是这些像素支配样式表的状态。
设备像素对用户来说几乎是无用的。用户可以放大缩小页面到自己可以阅读的合适的状态。然而,缩放不会对你造成麻烦。浏览器将自动伸缩你的CSS样式。
100%zoom
前面我举了例子,假设缩放水平是100%。现在稍微严格得定义了。
缩放水平100%的一个CSS像素就等于一个设备像素。
100%的缩放内容在以下说明中很有用,但是你不用过分担心它在日常的工作中。
屏幕大小(Screen size)
让我们看一些实例。我们从screen.width和screen.height开始。他们包含整个用户设备屏幕的高度和宽度。这两个维度用来测量设备的像素,因为它们永远不会改变:它们是显示屏的特征不是浏览器的特征。
窗口大小(Window size)
而你想知道的是浏览器内部窗口的大小。那就是当前用户用来CSS布局的可用窗口的空间。你可以用window.innerWidth和window.innerHeight这些维度来测量。
很明显,窗口内部宽度是用CSS像素来测量。随着用户放大浏览器窗口比例减少,你需要知道你的CSS布局多大才能放到浏览器的窗口。所以如果用户放大浏览器窗口,那么窗口的可用空间减少,同时反映出window.innerWidth/Height也在减小。
(这里有个例外,当用户放大窗口,window.innerWidth/Height不会减小:这是因为以设备像素为单位测量的。我们之后会看到)
注:浏览器窗口的尺寸包含滚动条的宽度和高度。
Scrolling offset (滚动偏移量)
Window.pageXOffset 和 window.pageYOffset,包含document水平的和垂直的滚动偏移量。这样你就可以知道用户滚动的量的。
这些属性也是以CSS像素为单位测量的。无论处于什么样的缩放状态,你都可以知道文档已经向上滚动了多少。
理论上,如果用户向上滚动并且放大,window.pageX/YOffset将会改变。然而当用户缩放窗口时,浏览器试图通过保持可视页面顶部的相同元素来保持网页的一致性。虽然这种方式并不是经常很有效,但是在实际应用中很有意义。
Window.pageX/Yoffset 并不是正真改变:已滚动出窗口的CSS像素的数量大致保持不变。
The viewPort
viewPort的功能是约束<html>元素,这是站点最上面的包含块。
听上去似乎有点模糊,这儿有个实例。假设有一个流式布局,其中一个元素的宽度是10%。现在当你调整浏览器的窗口时元素尺寸会整齐的收缩。这是怎么回事呢?
准确来说,该元素得到它父元素的10%的宽度。那就是<body>(还没有给body一个宽度)。所以问题是<body>的宽度是多少。
正常来说,所有的块级元素占据父元素宽度的100%(但有例外,这儿先忽略)。所以,<body>元素是和它的父元素<html>一样宽。
但是<html>元素有多宽?为什么它和浏览器的窗口一样宽。那是为什么宽度10%的元素会覆盖整个浏览器窗口的10%的宽度。所有的web开发者直觉得知道并用运这个事实。
你可能不知道的是在理论上这是怎么工作的。在理论上,<html>元素是受viewPort的宽度的约束的。<html>元素占据viewPort宽度的100%.
继而,viewPort就等同于浏览器的窗口:定义就是如此。ViewPort不是HTML结构,所以你不能通过CSS来影响它。它只是有着浏览器窗口的宽度和高度———在桌面上。在移动端事情就有点复杂。
结果
但是会有一些奇怪的结果。在这个站点,你可以看到其中一个。滚动条拉到顶部,放大两到三次,你就会看到这个站点会溢出浏览器窗口。滚动条拉到右边,你会发现顶部的蓝色条不再对齐。(站点地址:A tale of two viewports — part one (quirksmode.org))
这种行为是viewPort定义方式的结果。我给了顶部蓝色条100%的宽度,是什么的100%?是<html>元素的,<html>元素的宽度和viewPort的宽度一样,也和浏览器窗口的宽度一样。
重点是:当这个在100%放大状态下运行正常时,现在我们已经放大viewPort,它已经比我站点的宽度小了。对它来说这没什么问题,内容溢出了<html>元素,但是元素有overflow:visible,这意味着溢出的内容将会在任何情况下显示。
但是蓝色条并没有溢出,我给了它宽度100%,毕竟浏览器允许给它viewPort的宽度。它们不关心宽度,因为宽度现在太窄了。
文档宽度(document width)?
我很想知道的是整个页面的宽度是多少,包括那一点突出的部分。据我所知,不能找到那个值。(除非你计算页面上所有元素的宽度和margins,但是这很容易出错)
我开始相信我们需要JavaScript属性对来提供我称之为“document width”(很明显以CSS像素为单位)。
如果我们真的觉得很时髦独特,为何必将这个值暴露给CSS呢?我很乐意能够使我的蓝色条的100%的宽度是基于document的宽度,而不是<html>元素的宽度。(这一定很棘手,尽管它不可能实现,我也不会对此感到惊讶)
浏览器开发者,你们怎么想呢?
测量viewPort(Measuring the viewport)
你也许想知道浏览器的尺寸。它们将会被document.documentElement.clientWidh and -Height测量.
如果你知道你的dom,你知道document.documentElement 事实上是<html>元素:任何HTML document的根元素。然而,viewport是更高一级;它是包含<html>元素的元素。如果给<html>元素一个宽度。(我不推荐,但是这是可能的)
在那种情况下document.documentElement.clientWidth and Height可以提供viewport维度,而不是<html>元素。(这是一个特殊的规则只对元素,只对属性对起作用。在其他情况下,使用的是元素的宽度。)
所以,document.documentElement.clientWidth/-Height始终提供给viewport维度,与<html>元素维度无关。
但是viewport宽度的尺寸也是由window.innerWidth/Height提供的?是,也不是。
两个属性对在形式上存在差异:
Document.documentElement.clientWidth 和-Height不包含滚动条,而window.innerWidth/Height包含。这只不过是吹毛求疵。
事实上,我们有两个属性对是浏览器战争遗留的问题。
那时候,Netscape浏览器只支持window.innerWidth/Height ,IE浏览器只支持document.documentElelment.clientWidth and -Height.以后其他所有浏览器开始支持clientWidth and _Height,但是IE浏览器不支持window.innerWidth./Height.
在桌面上有两个可用的属性对是个小麻烦,但是在移动设备上确实一件好事,我们将会看到。
测量<html>元素(measuring the <html>element)
所以Document.documentElement.clientWidth/Height在任何情况下提供viewport尺寸。但是<html>元素自己的尺寸在哪里呢?它们存储在document.doumentElement.offsetWidth 和-heigt.
这些属性确实提供你作为块级元素访问<html>元素的方法;如过你设置一个width,offsetWidth 将会反映出来。
事件坐标(Event coordinates)
然后是事件坐标。当鼠标单击时,至少有5个属性对提供你事件发生的确切的位置信息。在我们的讨论中以下三条很重要:
- pageX/Y给出以CSS像素为单位<html>元素相关的坐标。
- clientX/Y给出以CSS像素为单位viewport相关的坐标。
- screenX/Y给出以设备像素为单位屏幕相关的坐标。
90%的时间使用pageX/Y;通常你会想知道document相关的事件位置。其他10%的时间会使用clientX/Y.而不需要知道屏幕相关的事件的坐标。
媒体查询(Media queries)
最后是有关媒体查询的。这个非常简单:你可以定义特殊的规则,当页面的宽度大于、等于或者小于某个确切的值时来执行这个规则。例如:
div.sidebar{
Width:300px;
}
@media all and (max-width:400px){
div.sidebar{
Width:100px;
}
}
现在元素的宽度是300px,当宽度小于400px时,元素的宽度是100px;
问题是:这儿测量的是谁的宽度,即以谁为基准测量的呢?
这儿有两个相关的媒体查询:width/height 和device-width/device-height.
- width/height使用同documentElement.clientWidth/Height相同的值(换句话说是viewport).它是以css像素为单位的。
- Device-width/device-height使用同screen.width/height相同的值(换句话说是屏幕)。它是以设备像素为单位的。
该用哪个呢?毫无疑问是width.网页开发者不对设备的宽度感兴趣;重要的时浏览器的窗口宽度。
所以在桌面上使用width而不是device-width.但是在手机上情况将糟得多。
总结
桌面浏览器得探索在此结束。第二部分内容将这些概念移植到移动浏览器上,强调与桌面浏览器得不同。