DOM系列:视窗、设备、滚动条和文档尺寸

发布于 大漠

在上一节中,学习了JavaScript如何获取和设置元素位置和尺寸相关的方法,另外在JavaScript的学习笔记当中也学习了视窗宽度、位置与滚动高度相关的JavaScript方法与属性。今天继续来学习DOM中相关的知识,这篇文章将学习视窗、设备、滚动条和文档等相关的尺寸。其实在前两篇文章中都有涉及这些知识,为了让DOM系列相关的知识更完善,所以再花点时间整理一些这方面的技术点,加强印象。

时至今日,构建Web应用程序是前端主要工作之一。这些Web应用程序要面对众多不同的设备终端,也就是说,我们需要让这些Web应用程序在各种屏幕、分辨率下都应该有一个较好的展示效果。

要将一个Web应用程序适配众多终端屏幕,需要知道的是有多少可用的空间。如果你接触过Web响应式设计(Web Responsive Design),就知道,Web浏览器客户端就可以很好的处理。最简单的方式就是使用CSS的媒体查询来处理,但也有很多同学通过JavaScript对最终的结果进行一些控制。不过,使用JavaScript来做的话,有许多计算的事情要做。当然,这些计算虽然是JavaScript来处理,但最终还是由浏览器本身来完成。

当涉及到使用JavaScript控制元素位置相关的交互内容时,不能仅依赖浏览器自动帮助我们做正确的事情。我们需要主动(人肉)地去做一些相关计算。听起来可怕,事实上并没有那么可怕,接下来的内容将告诉我们怎么通过JavaScript来做这些事情。当你阅读完这篇文章之后,你会惊叹的地说,原来就是这么的简单。

测量视窗的大小

不管是什么设备,都可以通过浏览器来查看Web页面。听起来很简单,对吧。从技术上讲,这并不完全准确。实际上,你可以通过浏览器的viewport查看Web页面。

Viewport

Viewport指的是网页的显示区域,也就是不借助滚动条的情况下,用户可以看到的部分网页大小,中文译为“视窗”(或“视口”)。正常情况下,viewport和浏览器的显示窗口是一样大小的。但是,在移动设备上,两者可能不是一样大小。

比如,手机浏览器的窗口宽度可能是640px,这时viewport宽度就是640px,但是网页宽度有1200px,正常情况下,浏览器会提供横向滚动条,让用户查看窗口容纳不下的560px。另一种方法则是,将viewport设成1200px,也就是说,浏览器的显示宽度还是640px,但是网页的显示区域达到1200px,整个网页缩小了,在浏览器中可以看清楚全貌。这样一来,手机浏览器就可以看到网页在桌面浏览器上的显示效果。

简单点来说,视窗是指你的浏览器中实际用来显示网页的部分,比如像下图这样:

拿Chrome浏览器来举例,viewport不包括浏览器的地址栏、状态栏或任何其他类型的用户界面。因为这些东西会占用空间。最后有一点很重要,viewport也不包括滚动条占用的空间

言外之意,根据浏览器开启的不同设置(比如浏览器窗口状态栏、地址栏等),你的视窗大小将有所不同:

正如前面提到的,viewport是可缩放的。既然可以缩放,那就具有可缩放的相关规则。在Web页面中,可以在HTML文件的<head>中像下面指定viewport相关的规则:

<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
</head>

上面代码指定,viewport的缩放规则是,缩放到当前设备的屏幕宽度(device-width),初始缩放比例(initial-scale)为1倍,禁止用户缩放(user-scalable)。

viewport 全部属性如下:

  • width: viewport的宽度
  • height: viewport的高度
  • initial-scale: viewport的初始缩放比例
  • maximum-scale: viewport的最大缩放比例
  • minimum-scale: viewport的最小缩放比例
  • user-scalable: viewport的是否允许用户缩放

事实上,在JavaScript中,咱们测量viewport的大小也很容易。调用document.documentElement对象的clientWidthclientHeight属性就可以测量出viewportwidthheight

比如下面这个示例的代码,让你调整浏览器窗口大小时会更新viewportWidth(视窗宽度)和viewportHeight(视窗高度)两个变量的值:

let displayViewportSize = (e) => {
    let viewportWidth = document.documentElement.clientWidth
    let viewportHeight = document.documentElement.clientHeight
    console.log(`viewportWidth: ${viewportWidth},viewportHeight: ${viewportHeight}`)
}

window.addEventListener('resize', displayViewportSize, false)

运行上面的代码,随着你改变浏览器窗口大小时,将会输出更改后视窗widthheight的值,如下所示:

从《DOM树和遍历DOM》一节中,我们知道document.documentElement是HTML的根元素,即<html>元素。clientWidthclientHeight属性可以用来获取元素边框内区域的大小。也就是说,document.documentElement.clientWidthdocument.documentElement.clientHeight分别获取的是html元素边框内区域的大小。如果你未接触过这两个属性,建议你花点时间阅读一下《获取元素位置和尺寸》一文。

如前所述,viewport的值不包括水平或垂直滚动条。但有时候,视窗大小的计算有可能也会包含滚动条的大小。如果计算的viewport大小包括了滚动条大小的话,咱们可以使用window.innerWidthwindow.innerHeight来进行计算。

注意,如果我们想测试整个浏览器的大小,那么可以使用window.outerWidthwindow.outerHeight两个属性。它们返回浏览器窗口整个大小,包括浏览器的标题栏、状态栏等等。

测量屏幕分辨率和尺寸

JavaScript中除了测量浏览器和视窗大小的属性之外,还有其他度量大小的属性。比如测量屏幕分辨率和尺寸的属性:

如果我们要测量屏幕的分辨率,可以使用下面这两对属性:

  • window.screen.widthwindow.screen.height 指的是显示器屏幕的宽度和高度,包括工具栏、状态栏等;
  • window.screen.availWidthwindow.screen.availHeight 指的是浏览器窗口在屏幕上可占用的空间(宽度和高度)

window.screen.widthwindow.screen.height理论上返回的屏幕完整的分辨率:

这两个属性没有考虑到屏幕(比如任务栏)占用的空间,所以它们不能准确地知道要处理多少像素。如果要知道屏幕实际有多大尺寸,应该使用window.screen.availWidthwindow.screen.availHeight

这两对属性在JavaScript中可以像下面这样使用:

let displayScreenResolution = () => {
    let fullWidth = window.screen.width
    let fullHeight = window.screen.height

    let availableWidth = window.screen.availWidth
    let availableHeight = window.screen.availHeight

    console.log(`fullWidth: ${fullWidth}px; fullHeight: ${fullHeight}px; availableWidth: ${availableWidth}px; availableHeight: ${availableHeight}px`)
}

window.addEventListener('click', displayScreenResolution, false)

测量document的尺寸

接下来,咱们再来看看document文档尺寸的大小。

可以通过document.bodyclientWidthclientHeight属性来获取文档的大小。从前面学习的知识中,我们知道document.body将获取的是<body>元素。

如果我们想要获取文档documentwidthheight,我们可以像这样写:

let displayDocumentSize = () => {
    let docWidth = document.body.clientWidth
    let docHeight = document.body.clientHeight

    console.log(`Document's Width: ${docWidth}px; Document's Height: ${docHeight}px`)
}

docWidthdocHeight变量存储的是documentwidthheight。如果你的document(也就是body元素)用的是百分比设置单位,你将看到你的文档的大小会根据视窗的大小变更。

比如,body设置样式:

body {
    width: 50%;
    height: 50%;
}

运行displayDocumentSize()函数之后,缩放浏览器,那么返回的docWidthdocHeight也会随之变化:

理论上,根文档元素是documentElement,也就是对应的<html>元素。而documentElement.clientWidthdocumentElement.clientHeight分别获取的是浏览器可视区域的widthheight。它包含了所有的内容,我们可以使用documentElement.scrollWidthdocumentElement.scrollHeight来测量它完整尺寸。

这些属性对于常规元素很有效。但是对于整个页面来说,这些属性并不能正常工作。在Chrome、Safari和Opera浏览器中,如果没有滚动条,那么就使用documentElement.scrollHeight,其获取的值甚至要比documentElement.clientHeight小。但对于常规元素来说,这是无稽之谈。

那么要得到一个可靠的窗口大小,我们应该这样使用:

let scrollHeight = Math.max(
    document.body.scrollHeight, document.documentElement.scrollHeight,
    document.body.offsetHeight, document.documentElement.offsetHeight,
    document.body.clientHeight, document.documentElement.clientHeight
);

滚动条尺寸

与滚动scroll相关的方法主要有window对象下的scrollXscrollYscrollToscrollElement对象下的scrollWidthscrollHeightscrollLeftscrollTop

有关于滚动条相关的API介绍,可以阅读JavaScript学习笔记系列中的《视口宽高、位置与滚动高度》一文。

有一点需要注意,大多数浏览器中可以使用documentElement.scrollLeftdocumentElement.scrollTop来获取文档滚动条,但Chrome、Safari和Opera存有bug(比如157855106133)。如此一来,我们应该使用document.body来替代document.documentElement

幸运的是,在JavaScript中有两个特殊属性:

  • window.pageXOffset:是scrollX的别名,返回文档/页面水平方向滚动的像素值
  • window.pageYOffset:是scrollY的别名,返回文档在垂直方向已滚动的像素值

注意,这两个属性是只读属性,不能修改。

除了上述提到的有关于滚动条的属性之外,还有window.scrollTo()window.scroll()window.scrollBy()等属性。

window.scrollTo方法用于将文档滚动到指定位置。它接受两个参数,表示滚动后位于窗口左上角的页面坐标。

window.scrollTo(x-coord, y-coord)

它也可以接受一个配置对象作为参数。

window.scrollTo(options)

配置对象options有三个属性:

  • top:滚动后页面左上角的垂直坐标,即 y 坐标
  • left:滚动后页面左上角的水平坐标,即 x 坐标
  • behavior:字符串,表示滚动的方式,有三个可能值(smoothinstantauto),默认值为auto

我们使用的时候可以像下面这样使用:

window.scrollTo({
    top: 1000,
    behavior: 'smooth'
});

window.scroll()方法是window.scrollTo()方法的别名。

window.scrollBy()方法用于将网页滚动指定距离(单位像素)。它接受两个参数:水平向右滚动的像素,垂直向下滚动的像素。

window.scrollBy(0, window.innerHeight)

上面代码用于将网页向下滚动一屏。

如果不是要滚动整个文档,而是要滚动某个元素,可以使用下面三个属性和方法。

  • Element.scrollTop
  • Element.scrollLeft
  • Element.scrollIntoView()

其中scrollIntoView()是HTML5新增的一个功能:元素滚动的API,功能是类似于锚点。

根据 MDN的描述,Element.scrollIntoView()方法让当前的元素滚动到浏览器窗口的可视区域内。

Element.scrollIntoView()方法还有一个变体,即:Element.scrollIntoViewIfNeeded()。该方法也是用来将不在浏览器窗口的可见区域内的元素滚动到浏览器窗口的可见区域。但如果该元素已经在浏览器窗口的可见区域内,则不会发生滚动。

有关于scrollIntoViewscrollIntoViewIfNeeded的 API 介绍,这里不深入下去。如果感兴趣的话,可以阅读这篇文章

总结

在《获取元素位置和尺寸》和《视口宽高、位置与滚动高度》两篇文章都有涉及JavaScript对视窗、滚动条、文档、元素大小尺寸相关的属性。由于自己是JavaScript的初学者,整理的相关学习笔记有点零乱。最后在这里简单的撸一下他们之间的关系。

属性名称 描述 备注
offsetParent 返回一个指向最近的(closest,指包含层级上的最近)包含该元素的定位元素 可以使用offsetParent获取最近的CSS位置(CSS-Positioned)的祖先
offsetLeft 当前元素左上角相对于offsetParent节点的左边界偏移的像素值  
offsetTop 当前元素相对于其 offsetParent 元素的顶部的距离  
offsetWidth 一个元素的布局宽度 测量包含元素的边框、水平线上的内边距、竖直方向滚动条以及CSS设置的宽度的值
offsetHeight 元素的像素高度,高度包含该元素的垂直内边距和边框,且是一个整数  
clientTop/Left 返回该方向的border宽度 该属性不包含元素的paddingmargin
clientWidth/Height 获取元素边框内区域的大小 包括了内容的宽度和padding,但不包含滚动条宽度
scroll 滚动窗口至文档中的特定位置 window.scrollTo 同样能高效地完成同样的任务
scrollLeft 读取或设置元素滚动条到元素左边的距离  
scrollTop 获取或设置一个元素的内容垂直滚动的像素数  
scrollWidth 返回该元素区域宽度和自身宽度中较大的一个  
scrollHeight 返回该元素内容高度 包括被overflow隐藏掉的部分,包含padding,但不包含margin
scrollX 返回文档/页面水平方向滚动的像素值 pageXOffsetscrollX的别名
scrollY 返回文档在垂直方向已滚动的像素值 pageYOffsetscrollY 的别名
window.innerHeight 浏览器窗口高度,如果存在水平滚动条,则包括滚动条  
window.outerHeight 浏览器窗口整个高度,包括窗口标题、工具栏、状态栏等  
window.innerWidth 浏览器窗口宽度,如果存在垂直滚动条,则包括滚动条  
window.outerWidth 浏览器窗口整个宽度,包括侧边栏,窗口镶边和调正窗口大小的边框  

扩展阅读

如果文章中有不对之处,烦请路过的大婶拍正。如果这篇文章对您有所帮助,路过的大爷可以打个赏,让我有更大的动力去创作更多有用的教程。(^_^)

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.fedev.cn/javascript/viewport-device-scroll-document-size.htmlNike Jordan Melo Shoes