这系列文章将解释 视口和各种重要元素的宽度是如何工作的,比如<html>
元素,以及窗口和屏幕。(how viewports and the widths of various important elements work, such as the element, as well as the window and the screen.)
概念:设备像素和CSS像素(device pixels and CSS pixels)
设备像素(device pixels)是任何设备的正式分辨率,并且(通常)可以通过screen.width/height
知道。
给某个元素宽度width:128px
,如果显示屏宽1024px
,最大化浏览器屏幕,则该元素将在显示器上填充显示八次。
然而,如果用户缩放,则该计算将会改变。比如用户缩放为200%,则宽度为128px
的元素将在1024px
宽显示器上显示的四次。
在现代浏览器中实现的缩放只不过是“伸展”像素而已。也就是说,元素的宽度不从128像素改变到256个像素;相反,实际像素的大小增加一倍了。形式上,即使元素恰好占用256个设备像素( device pixels)的空间,它的宽度仍为128个 CSS像素(CSS pixels)。
换句话说,缩放到200%可使一个CSS像素增长到一个设备像素大小的四倍(宽度的两倍,高度的两倍,总共产生四倍)。(In other words, zooming to 200% makes one CSS pixel grow to four times the size of one device pixels. (Two times the width, two times the height, yields four times in total).)
下面用图来阐明这个概念:
这是100%缩放级别的四个像素,这里没什么可看的。 CSS像素与设备像素完全重叠:
现在让我们缩小。CSS像素开始缩小,这意味着一个设备像素现在重叠了几个CSS像素:
如果放大,则相反。CSS像素开始增长,现在一个CSS像素与几个设备像素重叠:
重点是CSS像素。因为正是CSS像素决定了样式表的呈现方式。
设备像素对我们几乎没用。对于用户,他可能会将页面放大或缩小,直到他能轻松阅读。然而,缩放对我们无关紧要。浏览器将自动确保您的CSS布局被拉伸或压缩。
100% zoom
在100%缩放级别下,一个CSS像素等于一个设备像素。
100%缩放的概念在接下来的解释中非常有用,在日常工作中不用过于担心它。开发中通常会在100%的缩放中测试站点,即使用户放大或缩小,CSS像素的魔力也会确保你的布局保持在相同的比例。
屏幕尺寸(Screen size)
方法 screen.width
和screen.height
用于测量屏幕宽度和屏幕高度。这些尺寸是以设备像素来测量的,因为它们不会改变:它们是显示器的特性,而不是浏览器的特性。
Window size
浏览器窗口的内部大小。即当前可用于CSS布局的空间。可用 window.innerWidth
和 window.innerHeight
方法测量浏览器窗口的内部大小。
显然,窗口的内部宽度(the inner width of the window )以CSS像素为单位。布局中的内容放在浏览器窗口中,随着用户放大窗口,放在窗口中的内容就会减少,window.innerWidth/Height
的值也会减小。(这里的例外是Opera,其中window.innerWidth/Height在用户放大时不会减少:它们是以设备像素为单位测量的。这在桌面上是烦人的,但在移动上却是致命的,我们将在后面看到。)(Obviously, the inner width of the window is measured in CSS pixels. You need to know how much of your layout you can squeeze into the browser window, and that amount decreases as the user zooms in. So if the user zooms in you get less available space in the window, and window.innerWidth/Height reflect that by decreasing.)
注意,window.innerWidth/Height
包括滚动条。滚动条被认为是内部窗口的一部分。(这主要是出于历史原因。)
Scrolling offset
window.pageXOffset
和 window.pageYOffset
用于计算文档的水平和垂直滚动时的偏移量。因此,可以了解用户已经滚动了多少。这对属性也是以CSS像素(CSS pixels)为单位。
给几列div固定的高度来测试,主要代码如下:
<style>
* {
padding: 0;
margin: 0;
}
div {
color: white;
font-size: 30px;
text-align: center;
}
div:nth-child(1) {
height: 50px;
background: goldenrod;
}
div:nth-child(2) {
height: 150px;
background: pink;
}
div:nth-child(3) {
height: 200px;
background: khaki;
}
div:nth-child(4) {
height: 250px;
background: hotpink;
}
div:nth-child(5) {
height: 300px;
background: darkorange;
}
div:nth-child(6) {
height: 350px;
background: skyblue;
}
</style>
<body>
<div id="50px">height:50px</div>
<div id="150px">height:150px</div>
<div id="200px">height:200px</div>
<div id="250px">height:250px</div>
<div>height:300px</div>
<div>height:350px</div>
</body>
<script>
window.addEventListener('scroll', function (e) {
console.log(window.pageYOffset);
});
document.getElementById('50px').addEventListener('click', function () {
window.scrollTo(0, 50);
});
document.getElementById('150px').addEventListener('click', function () {
window.scrollTo(0, 200);
});
document.getElementById('200px').addEventListener('click', function () {
window.scrollTo(0, 400);
});
document.getElementById('250px').addEventListener('click', function () {
window.scrollTo(0, 650);
});
</script>
效果如下:
理论上,如果用户放大文档接着再向上滚动,window.pageX/Yoffset
将发生变化。但是,在用户缩放时,浏览器会通过将相同的元素保留在可见页的顶部来保持网页的一致性。这并不总是完美的工作,但这意味着在实践中window.pageX/Yoffset
并没有真正改变:不管文档是否被缩放,滚动出窗口的CSS像素的数量保持不变。
下面是放大文档后滚动文档,会发现 滚动出窗口的CSS像素的大小(大致)保持不变:
概念:视口(viewport)
在继续更多JavaScript属性之前,我们必须引入另一个概念:视口。<HTML>
元素是网页中最上面的块包含元素,视口的功能就是用来约束这个最上面的块包含元素。
听起来可能有点模糊,举个例子:
假设有个流式布局中的sidebar的宽度是 width:10%
。现在,当调整浏览器窗口的大小时,边栏整齐地增长或收缩。但这到底是怎么工作的呢?技术上,侧边栏的宽度为其父元素宽度的10%。这里父级元素是<body>
元素,此时<body>
元素没有设定宽度,因此问题变成了<body>
元素的宽度是如何有的。通常,所有的块级元素的宽度占其父节点宽度的100%(此处忽略特殊情况),因此,<body>
元素与其父对象<HTML>
元素一样宽。
那么<HTML>
元素又有多宽呢?它与浏览器窗口一样宽。这就是为什么sidebar的宽度width:10%
是整个浏览器窗口的10%。
所有的Web开发人员都默认这个事实。但可能不知道理论上是怎样的。在理论中,<HTML>
元素的宽度受视口宽度的限制。<HTML>
元素占用视口宽度的100%。
The viewport, in turn, is exactly equal to the browser window: it’s been defined as such. The viewport is not an HTML construct, so you cannot influence it by CSS. It just has the width and height of the browser window — on desktop. On mobile it’s quite a bit more complicated.
视口不受CSS影响,它不属于HTML结构,它的宽高由浏览器窗口决定。
视口的大小可以通过document.documentElement.clientWidth/clientHeight
取值,
了解DOM会知道:document.documentElement
实际上是<html>
元素,即任何HTML文档的根元素。但是,viewport更高一级,它是包含元素的元素。可以给元素一个宽度,这可能很重要。在这种情况下,document.documentElement.clientWidth/clientHeight
仍然取的是viewport的大小,而不是元素的大小(这是一条仅适用于此元素的特殊规则,仅适用于此属性对。在所有其他情况下,都使用元素的实际宽度/高度。)
测量< html >元素
clientWidth/clientHeigh
提供了所有情况下的视口(viewport)尺寸。但是如何获取元素本身的尺寸?通过document.documentElement.offsetWidth
方法可以获取到。这对属性真正使您可以访问块级元素<html>
;如果<html>
设置了宽度width
,则offsetWidth
取得的就是你设置的那个宽度值。
document.documentElement.clientWidth/clientHeight
测量<html>
元素尺寸(即整个page),单位是CSS像素(CSS pixels)。但是IE浏览器中获取的是视口的尺寸而不是<html>
元素的尺寸。
事件坐标(Event coordinates)
当发生鼠标事件时,能够获取有关事件确切位置的信息。其中有三个是我们经常关注的:
pageX/Y
提供了相对<HTML>
元素的坐标,单位是CSS像素(CSS pixels)。clientX/Y
提供了相对视口(viewport )的坐标,单位是CSS像素(CSS pixels)。screenX/Y
提供了相对屏幕(screen )的坐标,单位是CSS像素(CSS pixels)。
大多会用到pageX/Y
,知道相对于文档(document)的事件位置;少数时候会用到clientX/Y
;几乎用不到相对于屏幕的事件坐标。
IE浏览器不支持pageX/pageY
。
Media queries
只有当页面的宽度大于、等于或小于某个大小时,才能执行特殊的CSS规则。例如:
div.sidebar {
width: 300px;
}
@media all and (max-width: 400px) {
// styles assigned when width is smaller than 400px;
div.sidebar {
width: 100px;
}
}
现在边栏是300px宽,当宽度小于400px时,边栏变为100px宽。
问题是:这里的宽度是如何测量的?有两个相关的媒体查询:width/height
和设备宽度/设备高度(device-width/device-height)。
width/height
使用documentElement .clientWidth/Height
测量的值(即视口viewport),单位是CSS像素(CSS pixels)device-width/device-height
使用screen.width/height
测量的值(即屏幕screen),单位是设备像素(device pixels)
用哪一种?当然,这是一个不需要思考的问题。Web开发人员对设备的宽度不感兴趣;重要的是浏览器窗口的宽度。