原文链接:https://javascript.info/size-and-scroll-window,translate with ❤️ by zhangbao.
怎样查看浏览器窗口的宽度?怎样获得整个页面的高度?怎样用 JavaScript 滚动页面?
从 DOM 的视角来看,文档根元素是 document.documentElement
,对应 <html>
,具有前一章中我们说过的几何属性。在一些场景里,除此之外,它还有其他一些重要的方法和特性可以使用。
窗口的宽/高
窗口宽高,使用 document.documentElement
对象上的 clientWidth
、clientHeight
属性获得:
不要使用 **window.innerWidth/Height**``
虽然浏览器提供了
window.innerWidth/Height
接口,好像是我们想要的,那么它与document.documentElement
对象上的clientWidth/clientHeight
区别在哪里?如果窗口存在滚动条的话,是会占据内容区空间的。我们已经知道,
clientWidth/clientHeight
的结果是不包含滚动条的,也就是说,我们得到的是可视区内、可用内容的宽/高。但是,
widow.innerWIdth/innerHeight
属性值是包含滚动条的。如果有滚动条的话,下面两行就会打印不同的值。
alert( window.innerWidth ); // 窗口完整宽度
alert( document.documentElement.clientWidth ); // 减去滚动条后的窗口宽度
很多时候,我们需要的是窗口的可用宽度,在其中(不包含滚动条)渲染和定位元素。所以,我们应该用
documentElement.clientHeight/Width
更为精确。DOCTYPE`` 很重要
在我们的 HTML 文档里,如果我们没有使用文档声明
<!DOCTYPE html>
的话,顶级 的几个几何属性值可能会有差异(嗯,奇怪的事情总是有可能发生)。在现代 HTML 我们总是会写
DOCTYPE
,通常它对 JavaScript 代码不会产生影响,但在此处却是有影响的。
文档的宽/高
理论上来说,根元素是 document.documentElement
,也就是 <html>
,它表示整个页面文档。所以文档的宽高,我们自然想到,应该使用 documentElement.scrollWidth/scrollHeight
。
但这两个属性在除根元素之外的其他元素上使用没有问题,但在根元素上使用就会有点问题,不会得到想象中的结果。在 Chrome/Safair/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
);
alert('文档高度:' + scrollHeight );
为什么要这样?别问了,历史原因,这并不是一段“smart”逻辑。
得到当前滚动距离
普通元素获得滚动状态使用 elem.scrollLeft/scrollTop
。
那么对应页面呢?很多浏览器提供了 documentElement.scrollLeft/Top
,但是 Chrome/Safair/Opera 有 bug(比如 157855 和 106133),所以要使用用 document.body
而非 document.documentElement
。
幸运的是,我们无需记住这些特异的地方,因为在 window
对象上暴露了两个便捷的属性:pageXOffset/pageYOffset
:
alert('当前垂直方向滚动的距离:' + window.pageYOffset);
alert('当前水平方向滚动的距离:' + window.pageXOffset);
这两个属性是只读的。
滚动:scrollTo,scrollBy 和 scrollIntoView
重要
在滚动页面中的元素前,一定要保证要滚动元素已经在 DOM 树中创建了,否则是没有效果的。
普通元素可以通过设置 scorllLeft/scrollTop
的值来滚动元素。
我们也用相同方式,滚动页面:
在 Chrome/Safair/Opera 中:使用
docuement.body.scrollTop/Left
。其他浏览器:使用
document.documentElement.scrollTop/Left
。
所以为了让代码跨浏览器执行良好,我们需要写一些兼容代码。幸运的是,我们有更加简单和通用的解决方法:window.scrollBy() 和 window.scrollTo(pageX, pageY)。
scrollBy(x, y)
方法: 相对于现在的位置就行滚动的。例如,scrollBy(0, 10)
表示再向下滚动10px
距离。scrollTo(x, y)
方法:将文档左上角视为滚动时坐标系中的坐标原点,类似于scrollLeft
和scrollTop
。例如,我们将页面滚动到初始位置,可以用scrollTo(0, 0)
。
这两个方法在所有浏览器中都运行良好。
scrollIntoView
为了完整性,我们再说一个方法:elem.scrollIntoView(top)
。
调用 elem.scrollIntoView(top)
会让元素 elem
在可视区可见,参数是一个布尔值:
当
top
等于true
时(默认),元素滚动到窗口顶部,元素上边缘和窗口上边缘对齐。当
top
等于false
时,元素滚动到窗口底部,元素下边缘和窗口下边缘对齐。
禁止滚动
有时候我们不希望文档滚动。例如,我们需要在文档上显示一个蒙板,此时只与蒙板里的内容进行交互,不与文档交互。
为了让文档不能滚动,设置 document.body.style.overflow = 'hidden'
就够了。此时页面会固定在当前的滚动位置。
我们可以用相同的方式固定元素,不只是 docuemen.body
。
这种方式的一个缺点是,滚动条消失后,原来占据的位置就遭释放,导致内容区宽度变大,内容向外扩展了一些。
这看起来有点奇怪,不过我们可以使用 clientWidth
的值来确定滚动条消失前后的宽度,然后给 docuement.body
来个 padding
值来填补滚动条消失的空缺,让文档内容不至于偏移。
总结
几何:
获取文档可视区的宽/高(即内容区宽高,且不包含滚动条):
document.documentElement.clientWidth/Height
。获取整个文档宽/高:
let scrollHeight = Math.max(
document.body.scrollHeight, document.documentElement.scrollHeight,
document.body.offsetHeight, document.documentElement.offsetHeight,
document.body.clientHeight, document.documentElement.clientHeight
);
滚动:
获取页面当前滚动距离:
window.pageXOffset/pageYOffset
。滚动页面:
window.scrollTo(pageX, pageY)
:绝对滚动,相对于文档左上角滚动widnow.scrollBy(x, y)
:相对于当前位置的滚动,elem.scrollIntoView(top)
:滚动页面让元素可见(与窗口顶部/底部对齐)。
(完)