元素尺寸(~视图)

关于元素尺寸,一般地,有偏移量 offset、客户区 client 和滚动 scroll。


偏移量 offset(只读)

  • 所有偏移量属性都是只读的
  • 如果给元素设置了 display:none,则它的偏移量属性都为 0。
  • 每次访问偏移量属性都需要重新计算。重复访问偏移量属性需要耗费大量的性能,所以要尽量避免重复访问这些属性;如果需要重复访问,则把它们的值保存在变量中,以提高性能。

主要涉及 4 个属性:offsetLeft、offsetTop、offsetHeight、offsetWidth和一个偏移参照 — 定位父级 offsetParent。


[1] 定位父级 offsetParent

人们并没有把 offsetParent 翻译为偏移父级,而是定位父级,很大原因是 offsetParent 与定位有关。

offsetParent 的定义是:与当前元素最近的经过定位(不等于 static)的父级元素,主要分为下列几种情况:

  • 元素自身有 fixed 定位,offsetParent 的结果为 null( firfox存在兼容性问题,返回 <body>)。
  • 元素自身无 fixed 定位,且父级元素都未经过定位,offsetParent 的结果为 <body>。
  • 元素自身无 fixed 定位,且父级元素存在经过定位的元素,offsetParent 的结果为第一个定位元素。
  • <body>元素的 parentNode 是 null。

[2] 偏移量

偏移量,主要涉及 offsetHeight、offsetWidth、offsetLeft、offsetTop 这 4 个属性。

若存在垂直滚动条,offsetWidth包括垂直滚动条的宽度;若存在水平滚动条,offsetHeight包括水平滚动条的高度。

offsetWidth:表示元素在水平方向上占用的空间大小,无单位(以像素px计)

offsetHeight:表示元素在垂直方向上占用的空间大小,无单位(以像素px计)

offsetTop:表示元素的上外边框至offsetParent元素的上内边框之间的像素距离

offsetLeft:表示元素的左外边框至offsetParent元素的左内边框之间的像素距离


[3] 页面偏移:要知道某个元素在页面上的偏移量,将这个元素的offsetLeft和offsetTop与其offsetParent的相同属性相加,并加上offsetParent的相应方向的边框,如此循环直到根元素,就可以得到元素到页面的偏移量。

在默认情况下,IE8-如果使用 currentStyle() 方法获取<html> 和 <body>(甚至普通div元素)的边框宽度都是 medium,而如果使用 clientLeft(或clientTop) 获取边框宽度,则是实际的数值。


客户区 Client(只读)

客户区 client,指的是元素内容及其内边距所占据的空间大小;滚动条不计算在内。


  • clientHeight:返回元素节点的客户区高度
  • clientWidth:返回元素节点的客户区宽度
  • clientLeft:返回左边框的宽度
  • clientTop:返回上边框的宽度

如果display为inline时,clientLeft属性和clientTop属性都返回0。


[ 页面大小 ] 常用 document.documentElement 的 client属性来表示页面大小( 不包含滚动条宽度)。

  • 在IE7-浏览器中,<html>元素默认存在垂直滚动条。

  • 另一对常用的表示页面大小的属性是 window.innerHeight 和 innerWidth属性( 包含滚动条宽度)。

innerHeight和innerWidth表示的是浏览器窗口大小减去菜单栏、地址栏等剩余的页面尺寸,由于滚动条是属于页面的,所以包含滚动条。但,IE8-不支持innerHeight和innerWidth属性。

如果没有滚动条,这两类属性在电脑端表示同样的值,但是却表示不同的含义。在移动端,innerWidth和innerHeight表示的是视觉视口,即用户正在看到的网站的区域;而document.documentElement.clientWidth和clientHeight表示的是布局视口,指CSS布局的尺寸。

页面的客户区大小和页面的实际大小是不同的,页面的实际大小将由 scroll 滚动大小来表示。


[3] 注意事项

  • 所有客户区client属性都是只读的。
  • 如果给元素设置了display:none,则客户区client属性都为0。
  • 每次访问客户区client属性都需要重新计算,重复访问需要耗费大量的性能,所以要尽量避免重复访问这些属性。如果需要重复访问,则把它们的值保存在变量中,以提高性能。

滚动 Scroll

[1] 滚动宽高(只读)

  • scrollHeight:表示元素的总高度,包括由于溢出而无法展示在网页的不可见部分
  • scrollWidth:表示元素的总宽度,包括由于溢出而无法展示在网页的不可见部分

  • 没有滚动条时,scrollHeight与clientHeight属性结果相等,scrollWidth与clientWidth属性结果相等。
  • 存在滚动条时,但元素设置宽高大于等于元素内容宽高时,scroll和client属性的结果相等。
  • 存在滚动条,但元素设置宽高小于元素内容宽高,即存在内容溢出的情况时,scroll 属性大于 client 属性

[ 页面尺寸 ] document.documentElement.clientHeight表示页面的可视区域的尺寸,

而 document.documentElement.scrollHeight 表示 html 元素内容的实际尺寸。但是由于各个浏览器表现不一样:

  • html元素没有滚动条时,IE和firefox的client和scroll属性始终相同,且返回可视区的尺寸大小;而safari和chrome表现正常,clientHeight返回可视区域大小,而scrollHeight返回元素内容大小。
  • html存在滚动条时,各浏览器表现正常。clientHeight返回可视区域大小,而scrollHeight返回元素内容大小。

[ 兼容 ]  因此要取得文档实际高度时,要取得<html>元素的scrollHeight和clientHeight的最大值。


[2] 滚动长度(可写)

  • scrollTop:表示被隐藏在内容区域上方的像素数。元素未滚动时,scrollTop的值为0,如果元素被垂直滚动了,scrollTop的值大于0,且表示元素上方不可见内容的像素宽度。
  • scrollLeft:表示被隐藏在内容区域左侧的像素数。元素未滚动时,scrollLeft的值为0,如果元素被水平滚动了,scrollLeft的值大于0,且表示元素左侧不可见内容的像素宽度。

当滚动条滚动到内容底部时,符合以下等式

与 scrollHeight 和 scrollWidth 属性不同的是,scrollLeft 和 scrollTop 是可写的。


[ 页面滚动 ] 理论上,通过document.documentElement.scrollTop和scrollLeft可以反映和控制页面的滚动;但是chrome和safari浏览器是通过document.body.scrollTop和scrollLeft来控制的。

所以,页面的滚动高度兼容写法是:


[ 代码示例 - 回到顶部?!] 可以利用scrollTop来实现回到顶部的功能


[3] 页面滚动长度(只读):window的两个只读属性可以获取整个页面滚动的像素值:pageXOffset和pageYOffset。

  • pageXOffset:表示水平方向上页面滚动的像素值。
  • pageYOffset:表示垂直方向上页面滚动的像素值。


[4] 滚动方法

[4-1] scrollTo(x,y):滚动当前window中显示的文档,让文档中由坐标 x 和 y 指定的点位于显示区域的左上角。

[4-2] scrollBy(x,y):滚动当前 window 中显示的文档,x 和 y 指定滚动的相对量。

[ 代码示例 ] 利用 scrollBy() 加 setInterval 计时器实现简单的快速滚动功能。

[4-3] Element.scrollIntoView():滚动当前元素,进入浏览器的可见区域

该方法可以接受一个布尔值作为参数。

  • 如果为 true(默认),表示元素的顶部与当前区域的可见部分的顶部对齐(前提是当前区域可滚动);
  • 如果为 false,表示元素的底部与当前区域的可见部分的尾部对齐(前提是当前区域可滚动)。


[5] 滚动事件

scroll 事件是在 window 对象上发生的,它表示的是页面中相应元素的变化。当然,也可以用在有滚动条的元素上。


元素视图方法

偏移量 offset、客户区 client和滚动 scroll,主要从属性的角度来对元素尺寸信息进行获取和修改;

以下为元素视图的三个方法:getBoundingClientRect()、getClientRects()和elementFromPoint()。


[1] getBoundingClientRect()

判断一个元素的尺寸和位置最简单的方法就是使用 getBoundingClientRect()。

Element.getBoundingClientRect()方法返回一个对象,该对象提供当前元素节点的大小、它相对于视口(viewport)的位置等信息。但是,各个浏览器返回的对象包含的属性不相同.

问题在于,该方法返回的width和height是客户区宽高client,还是滚动宽高scroll,或者是偏移宽高offset,或者是设置宽高呢?

由代码结果看出,该方法返回的宽高是偏移宽高offset。

下面来分析top、left、right、bottom这四个值

top:   元素顶部相对于视口的纵坐标

left:  元素左边界相对视口的横坐标

right: 元素右边界相对视口的横坐标

bottom:元素底部相对于视口的纵坐标

[注意]该方法的所有属性值都没有单位,且给定的是元素在页面中相对于视口的位置

问题又来了,相对于视口和相对于页面有什么区别。理论上,与absolute和fixed的区别类似,但表现上与它们正相反。发生滚动时,fixed元素保持不动是为了保持与视口的原始距离;而发生滚动时,getBoundingClientRect()方法的top、left、right、bottom这四个值相应的发生改变,是因为元素位置移动了,与视口距离自然也改变了

bug

IE7-浏览器把视口的左上角坐标设置为(2,2),其他浏览器则将(0,0)作为起点坐标。

兼容

可以利用IE7-浏览器中特性节点的specified属性实现浏览器识别


[2] getClientRects()

getClientRects() 方法与 getBoundingClientRect() 不同,该方法是一个返回元素的数个矩形区域的类数组对象。每个类数组对象的参数与 getBoundingClientRect() 方法相同,每个矩形都有 bottom、height、left、right、top 和 width 六个属性,表示它们相对于视口的四个坐标,以及本身的高度和宽度。

如果应用于块级元素,则 getClientRects()[0] 和 getBoundingClientRect() 的属性返回相同的值,且 IE7- 浏览器在 getClientRects() 方法中,同样存在视口左上角坐标被设置为 (2,2) 的 bug。

实际上,该方法主要用于内联元素,内联元素有多少行,该方法返回的对象有多少个成员。这个方法主要用于判断行内元素是否换行,以及行内元素的每一行的位置偏移。


[3] elementFromPoint()

getBoundingClientRect(x,y)方法使我们能在视口中判定元素的位置。但有时我们想反过来,判定在视口中的指定位置上有什么元素。这可以用Document对象的elementFromPoint()方法来判定。传递X和Y坐标(相对于视口),该方法选择在指定坐标的最上层和最里层的Element对象。如果指定的点在视口以外,elementFromPoint()返回null。

[注意]最上层是指z-index最大的元素;最里层是指最里层的子元素。

这个方法可以用来检测元素是否发生重叠或是碰撞。