📓The Modern JavaScript Tutorial: Element size and scrolling JavaScript 译文

张宝 发布于 6个月前

举一个例子:

<div id="example">
  ...Text...
</div>
<style>
  #example {
    width: 300px;
    height: 200px;
    border: 25px solid #E8C48F;
    padding: 20px;
    overflow: auto;
  }
</style>

#example 这个元素包含宽、高、边框和内边距(没有外边距,是因为外边距不是元素的一部分)。

用一张图来说明,是这样的。

⚠️ 注意滚动条。

#example 是有滚动条的,而且 滚动条占据的是内容区的空间,而不是内边距。

来,我们说明一下:#example 的内容区宽度我们设置为 300px,但是滚动条占据了 16px 的宽度空间(当然,并不一定,要视具体的设备和浏览器限制),所有最终内容区的有效宽度是 300 - 16 = 284px

几何属性

几何属性就是像宽、高啦这样的一些数值属性,单位都是像素。

这有一张图,大致说明了这些属性。

offsetParent、offsetLeft/Top

这些属性很少需要,但仍然是“最外层”的几何属性,所以我们将从这些属性开始。

offsetParent 用来获得最近的祖先元素。包括:

  1. 定义元素(position 的值为 absoluterelativefixed)。
  2. 或者 <td><th></table>
  3. 或者 <body>

在大多数实际情况下,我们可以使用 offsetParent 来获取最近的定位祖先元素。 offsetLeft / offsetTop 提供相对于祖先元素左上角的 x/y 坐标。

在下面的例子里,<main> 是内部 divoffsetParentoffsetLeft/offsetTop 是相对于 <main> 左上角的偏移距离(180)。

<main style="position: relative" id="main">
  <article>
    <div id="example" style="position: absolute; left: 180px; top: 180px">...</div>
  </article>
</main>
<script>
  alert(example.offsetParent.id); // main
  alert(example.offsetLeft); // 180 (note: a number, not a string "180px")
  alert(example.offsetTop); // 180
</script>

有几个场景下,offsetParent 的值为 null

  1. 未显示元素(display: none 或者在不在文档中的)。
  2. <body><html>
  3. position: fixed 定位的元素。

offsetWidth/Height

下面转向元素本身。

元素的 offsetWidth/Height 属性值包含边框,可以认为是元素“外部”宽/高。

上图中,元素的 offsetWidth390offsetHeight290

⚠️ 未显示元素几何属性值为 0/null

几何属性只在显示属性上使用是有用的。

如果一个元素(或任何祖先元素)的是 display: none 的,那么它的几何属性值是 0 或者 null

例如:offsetParent 值为 nulloffsetWidthoffsetHeight 的值为 0

我们可以根据这个特性,检查一个元素是否是隐藏的。

function isHidden(elem) {
  return !elem.offsetWidth && !elem.offsetHeight;
}

当然,空标签元素检查也会返回 true(比如一个空的 div)。

clientTop/Left

clientTopclientLeft 属性值可以认为是元素边框的大小。

但也不全是,如果内部有滚动条的话……clientLeft 还包含滚动条的宽度。

clientWidth/Height

clientWidth/Height 包含元素内容区宽度:包含内边距,但是不包含滚动条占据的空间。

上图里,元素的宽是 300px,内边距是 20px,但是因为有滚动条,所以有效宽度是 300-16=284px。因此 clientWidth 的值是 20 + 284 + 20 = 324px

如果没有内边距的话,clientWidth/Height 就是指内容区(conetnt area)空间----边框内、但不包含滚动条(有的话)。

scrollWidth/Height

scrollWidth/Height 属性表示元素的完全的宽、高(包括隐藏部分的)。

下面代码,让元素的高度设定为完全的高度值。

// expand the element to the full content height
element.style.height = `${element.scrollHeight}px`;

scrollLeft/scrollTop

scrollLeft/scrollTop 并不是只读的,也可写。

elem.scrollTop += 10

让元素向下滚动 10px。将 scrollTop 设置为 0 或者 Infinity 让元素响应地滚动到文档顶部或者底部。

不要用 getComputedStyle 获得元素宽高

我们可以用 getComputedStyle 获得元素宽高,那为什么不用呢?

let elem = document.body;

alert( getComputedStyle(elem).width ); // show CSS width for elem

有两个原因,说明使用 getComputedStyle 带来的缺点:

  1. 首先,CSS width/height 属性的取值依赖于 box-sizing 属性,box-sizing 属性的改变可能会影响到程序运行。
  2. 其次,CSS width/height 可能是 "auto",而不是一个数值。比如,行内元素的宽。
<span id="elem">Hello!</span>

<script>
  alert( getComputedStyle(elem).width ); // "auto"
</script>

而且 getComputedStyle(elem).width 在不同浏览器中行为还不一样:一些浏览器(像 Chrome)返回的是去掉滚动条的宽(不包含内边距),而另一些(FireFox)计算出来的宽是包含滚动条的(不包含内边距)。

getComputedStyle 的的局限只是在 width 属性上,其他属性取值都是没问题的。

总结

元素具有以下一些几何属性:

  • offsetParent:最近的定位祖先元素或者 <td><th><table><body>
  • offsetLeft/offsetTop:相对于 offsetParent 左上角的定位坐标。
  • offsetWidth/offsetHeight:包含元素边框的“外”宽高。
  • clientLeft/clientTop:(用太少,不说了)。
  • clientWidth/clientHeight:元素内容区宽/高,包含内边距,不包含滚动条。
  • scrollWidth/scrollHeight:元素的完整宽高(包含隐藏起来的部分),也是包含内边距,不包含滚动条的。
  • scrollLeft/scrollTop:元素相对于自身初始左上角的位置滚动的距离。

除了 scrollLeft/scrollTop 其他属性都是只读的。

(完)


登录参与评论