pc端和移动端的“窗口”(viewport)故事(part1)
A tale of two viewports — part one
在以下的系列文章中,我将为大家解释浏览器中的视窗和一些重要的元素的尺寸是如何起作用的,如:大家最熟悉的html元素以及window和screen对象。
这篇文章作是本系列的第一部分,是关于台式电脑的浏览器的,主要目的是为后续的移动端浏览器的讨论奠定一个基础。大部分的web开发者能够凭直觉理解大部分台式机浏览器的概念。在移动端我们也将遇到一样的概念,不过对于这些人人都知道的概念进行更加复杂和预先的讨论将会极大地帮助大家理解移动端浏览器。
概念:设备像素和css像素
首先要理解的概念是理解css像素以及与设备像素之间的差异。
设备像素:设备像素是我们直觉上最容易理解的。这些像素是描述了所在设备的分辨率,可以通过screen.width/height来获取。假定给定一个元素的宽度为width:128px,显示器宽度是1024px,无缩放的情况下,要8个元素才能填满整个显示器。如果用户缩放到200%,只要4个元素就可以填满整个显示器。
现代浏览器中的缩放仅仅是拉伸像素。这意味着元素的宽度不会从128px变为256px,而是实际的像素尺寸变成双倍。元素的宽度仍然为128 css px,即使他占据了256个设备像素的空间。换句话说,缩放到200%使得一个css像素变成4倍的设备像素大小。
下面的图将解释这个概念。
(1)无缩放的4像素的图。css像素与设备像素完全重合 一个css像素等于一个设备像素
(2)缩小 css像素开始收缩,一个设备像素覆盖多个css像素
(3)放大 css像素开始变大,一个css像素覆盖多个设备像素
但是我们只关注渲染页面的css像素。设备像素对于前端工程师来说几乎没有什么用处。只有用户会缩放页面使得阅读舒适。浏览器会根据你的css样式去自适应页面元素的大小以及保持特定的元素比例。
屏幕尺寸
screen.width 和 screen.height分别表示用户屏幕的宽高。他们都是以设备像素衡量的,因为设备像素是不会改变的,设备像素是显示器的属性,与浏览器无关。
但是屏幕尺寸对我们来说没有什么作用,除非你想要建立一个web统计数据库。
window大小
我们感兴趣的是浏览器窗口的内部尺寸。这是用户当前css层可用的实际空间,分别是 window.innerWidth 和 window.innerHeight。
显然,窗口的内部宽度是用css像素衡量的。当用户放大的时候,你可以得到更少的窗口空间,window.innerWidth 和window.innerHeight将会变小。
(Opera浏览器是个例外, window.innerWidth/Height不会随着用户放大而缩小,他们以设备像素衡量。这在台式机中很烦人,在移动端中是致命的)需要注意的是,测量的widths 和 heights是包括滚动条的。
Scrolling offset
window.pageXOffset 和 window.pageYOffset 分别是document的横向和纵向的滚动距离。
这些也是以css像素衡量的。你可以知道文稿被滚动了多少,不论它是否被缩放。
理论上,如果用户页面向上滚动然后放大,window.pageX/YOffset会改变。然而,当用户缩放时,浏览器想要通过使得可见页面的顶部是同样的元素来保证网页的一致性。这通常并不能表现的很好,不过这使得实际的 window.pageX/YOffset 不会发生改变。
concept:viewport
viewport的作用是限制<html>
元素,是最高级的块级容器。html的宽度是受view的宽度限制的,是viewport宽度的100%。
viewport正好等于浏览器窗口。
consequences
这样的限制机制会导致一系列的浏览器显示效果。如下,将屏幕滚动到顶部,然后放大2——3次使得网页的内容溢出浏览器窗口。然后滚动到最右侧,此时上面的的蓝色条块布局出现异常。
这就是viewport的定义导致的影响。蓝色条的width为100%。相对于什么元素的100%?相对于html元素的话,应该是与viewport等宽,也等于浏览器窗口宽度。关键的点是这在无缩放的情况下显示正常,此时放大的页面的使得viewport小于整个网页内容的宽度,网页内容溢出了html元素,但是这个元素是有益溢出的属性:overflow:visible,这表示溢出的内容不论怎样都会显示。但是蓝色条没有溢出。他的宽度为100%,浏览器会将它的宽度设为与viewport等宽。
document width?
ducument width表示网页内容的总宽度,但是没有这个css属性。
Measuring the viewport
viewport可以通过document.documentElement.clientWidth 和 -Height得到。
如果你了解dom,就会知道document.documentElement事实上是html元素,它是任何html文档的根元素。然而,viewport是更高一层的,它包括html元素。如果要给定html元素宽度,将会与viewport有关。在那种情况下,document.documentElement.clientWidth 和 -Height仍然是viewport的尺寸,而不是html元素。(这是viewport一个特殊的属性,其他的元素都是元素本身的属性)
因此,document.documentElement.clientWidth 和 -Height总是表示viewport的尺寸,与html元素无关。
Two property pairs
window.innerWidth/Height难道不表示vewport的尺寸么?是,也不是。document.documentElement.clientWidth 和 -Height不包括滚动条,而window.innerWidth/Height包括。这两个属性的出现源于浏览器大战。 Netscape仅仅支持 window.innerWidth/Height ,ie仅仅支持document.documentElement.clientWidth and -Height。从此,所有的其他浏览器都支持clientWidth/Height,但是ie没有选择window.innerWidth/Height。在台式机中,拥有这两种属性是不友好的,但是在移动端中应该庆幸。
Measuring the element
因此,clientWidth/Height在任何情况下都表示viewport的尺寸。html的尺寸则用 document.documentElement.offsetWidth 和-Height来表示。如果你设置html的尺寸,offsetwidth等会反应出来。
Event coordinates
1.pageX/Y 表示事件位置相对于html元素的css像素坐标位置。
2.clientX/Y 表示事件位置相对于viewport的css像素坐标位置。
3.screenX/Y 表示事件位置相对于screen的设备像素的坐标位置。
pageX/Y
lientX/Y
screenX/Y
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;
}
}
有两种相关的媒体查询: width/height 和 device-width/device-height。
1.width/height 与 documentElement .clientWidth/Height值相等(相对于viewport,css像素);
2.device-width/device-height 相对于screen,与screen.width/height的尺寸一致,是设备像素。
use width and forget device-width — on desktop
Conclusion
以上是关于台式机浏览器的一些属性和特征,关于移动端的见part2.
翻译原文地址:https://quirksmode.org/mobile/viewports.html