谈谈元素的宽高尺寸

引语

在与dom节点打交道时, 常常需要用到获取dom的尺寸和位置. 有时候不能正确获取时, 只是查找下资料, 现在想系统的总结一下, 以免下次再忘记,毕竟好记性不如烂笔头.

获取宽高,位置

获取一个元素的大小,常常是通过它的clientX, offsetX, scrollX属性来获取的(其中X表示width,height,left,top), 他们之间有什么样的区别呢?

clientX offsetX scrollX
clientWidth offsetWidth scrollWidth
clientHeight offsetHeight scrollHeight
clientLeft offsetLeft scrollLeft
clientTop offsetTop scrollTop

这些属性的笼统特征区别是:
client:元素内容+内边距 大小,不包括边框、外边距、滚动条部分
offset:元素内容+内边距+边框 不包括外边距, 包括滚动条部分
scroll:与元素的滚动相关

clientX,offsetX,scrollX

clientX

属性 说明
clientWidth 元素可视区域的宽度,包含内边距,但不包括垂直滚动条、边框和外边距
clientHeight 元素可视区域的高度,包含内边距,但不包括水平滚动条、边框和外边距
clientLeft 元素左边边框的宽度,等于border-left
clientTop 元素顶部边框的宽度,等于border-top

offsetX

关于offsetLeft和offsetTop, 还有一个重要的相关概念offsetParent,它返回一个指向最近的包含该元素的已定位元素(relative,absolute)。如果没有定位的元素,则 offsetParent 为最近的 table元素对象或根元素(标准模式下为 html;怪异模式下为 body)。当元素的 style.display设置为 none 或定位为fixed时,offsetParent 返回 null

属性 说明
offsetWidth 在clientWidth的基础上, 加上边框和滚动条的高度
offsetHeight 在clientHeight的基础上, 加上边框和滚动条的高度
offsetLeft 当前元素到其offsetParent 节点的左边的距离
offsetTop 当前元素到其offsetParent 节点的上边的距离

scrollX

属性 说明
scrollWidth 元素完整的宽度和内边距,这个宽度度包括肉眼看不见、溢出、被窗口遮挡的部分
scrollHeight 元素完整的高度和内边距,这个高度包括肉眼看不见、溢出、被窗口遮挡的部分
scrollLeft 可以读取或设置元素滚动条到元素左边的距离,元素被卷起来的宽度;获取元素若为body时,document.body.scrollLeft == window.scrollX;
scrollTop 元素的 scrollTop 值是这个元素的顶部到它的最顶部可见内容(的顶部)的距离的度量。当一个元素的内容没有产生垂直方向的滚动条,那么它的 scrollTop 值为0;获取元素若为body时,document.body.scrollTop == window.scrollY;

以上的12个属性当中, 除了scrollLeft和scrollTop是可读可写的, 其他都是只读属性. 他们可以用下面这幅图来区分一下.

元素.style.属性

需要注意:

  1. 用这种方法获取元素属性width, height等, 有时是获取不到的,它只能够获取到该元的行内样式.
  2. 返回除了数字还有单位, 而且单位不一定是px,或者返回文字如”auto”, 比如设置的width: 10rem, 那么dom.style.width返回的值时”10rem”.而且使用这个方法给属性值时候需要带单位的要带上单位,否则不生效。

window.getComputedStyle(dom)

window.getComputedStyle(dom)这个重量级嘉宾是js里提供元素属性最全的方法,里面包含几百个属性, 还能获取非内联样式以及隐藏元素的属性, 返回的是最为精确的宽高值(包含小数点),语法如下:

window.getComputedStyle(element).getPropertyValue(属性)

注意: .IE不支持window.getComputedStyle(),对应的是element.currentStyle;

getBoundingClientRect()

这个方法返回一个矩形对象,包含6个属性:left、right、top、bottom、widthheight。这些属性给出了元素在页面中相对于视口的位置

var rect = d.getBoundingClientRect();
rect.left;    //50
rect.right;    //350
rect.width;    //300
rect.top;    //50
rect.bottom;    //350
rect.height;    //300

即通过 getBoundingClientRect() 获取的宽高,它包含的内容和 offsetWidth/offsetHeight 是一致的, 唯一的不同就是,getBoundingClientRect() 返回的是最为精确的宽高值.(不会四舍五入为整数)

jquery 的宽高属性

属性 说明
$(window).height()/.width() 获取浏览器显示区域(可视区域)的高度/ 宽度
$(document).height()/.width() 获取页面的文档高度/宽度
$(document.body).height()/.width() 浏览器当前窗口文档body的高度/宽度
$(document).scrollTop()/.scrollLeft() 获取滚动条到顶部/左边(被卷起来)的垂直高度/宽度
$(obj).width()/.height() 获取或设置元素的宽度/高度
$(obj).innerWidth()/.innerHeight() 获取或设置元素的宽度/高度(width/height + padding)
$(obj).outerWidth()/.outerHeight() 获取或设置元素的宽度/高度(width/height + padding + border)
$(obj).outerWidth(true)/.outerHeight(true) 获取或设置元素的宽度/高度(width/height + padding + border + margin)
$(obj).offset().top/.offset().left 不含滚动条时,返回某个元素的上/左边界到body最顶部/最左边的距离;含滚动条时,返回当前元素的上/左边界到它的包含元素的上边界的偏移,

注意事项

box-sizing的设置与隐藏元素

以下是一个例子

<div id="div" style="width: 100px; height: 100px;">
<p>这是一个p元素</p>
</div>

  <style>
    div {
      padding: 10px;
      margin: 10px;
      border: 10px solid black;
      background: red;
    }
    p {
      margin: 0;
      padding: 0;
      background: blue;
    }
  </style>
function getSizeInfo () {
    var div = document.getElementById('div');
    var size = `clientWidth: ${div.clientWidth},
    clientHeight: ${div.clientHeight},
    offsetWidth: ${div.offsetWidth},
    offsetHeight: ${div.offsetHeight},
    scrollWidth: ${div.scrollWidth},
    scrollHeight: ${div.scrollHeight},
    style.height: ${div.style.height},
    style.width: ${div.style.width},
    getComputedStyle的width值: ${ window.getComputedStyle(div).getPropertyValue('width')},
    getComputedStyle的height值: ${ window.getComputedStyle(div).getPropertyValue('height')}`
    return size
}

// div的box-sizing是content-box时,
"clientWidth: 120,
  clientHeight: 120,
  offsetWidth: 140,
  offsetHeight: 140,
  scrollWidth: 120,
  scrollHeight: 120,
  style.height: 100px,
  style.width: 100px, 
  getComputedStyle的width值: 100px, 
  getComputedStyle的height值: 100px"

// div的box-sizing是border-box时,
"clientWidth: 80,
clientHeight: 80,
offsetWidth: 100,
offsetHeight: 100,
scrollWidth: 80,
scrollHeight: 80,
style.height: 100px,
style.width: 100px, 
getComputedStyle的width值: 100px, 
getComputedStyle的height值: 100px"

用表格来总结一下

属性 content-box border-box display:none
clientWidth/clientHeight content + padding content + padding 0
offsetWidth/offsetHeight content + padding + border content + padding + border 0
scrollWidth/scrollHeight content + padding + 溢出内容 content + padding + 溢出内容 0
style.height/style.width content content + padding + border 前面两个之一
window.getComputedStyle content content + padding + border 前面两个之一

出现滚动条时默认滚动轴的占宽

content + padding + border + margin加在一起时显示的才是一个完整的 dom, 但是当里面的内容超过限制时便会出现滚动轴, 而滚动轴默认是占用padding的空间, 当padding的宽度小于滚动条, 那么滚动条多出来的部分将占用content的宽度.

把上面的例子的p标签的css改为width:500px; height:500px; 出现一个宽15厘米的滚动条, 他们的属性会发生什么变化呢?

// div的box-sizing是content-box时,
"clientWidth: 105,
clientHeight: 105,
offsetWidth: 140,
offsetHeight: 140,
scrollWidth: 510,
scrollHeight: 520,
style.height: 100px,
style.width: 100px, 
getComputedStyle的width值: 85px, 
getComputedStyle的height值: 85px"

//  div的box-sizing是border-box时,
"clientWidth: 65,
clientHeight: 65,
offsetWidth: 100,
offsetHeight: 100,
scrollWidth: 510,
scrollHeight: 520,
style.height: 100px,
style.width: 100px, 
getComputedStyle的width值: 100px, 
getComputedStyle的height值: 100px"

用表格来总结一下

属性 content-box border-box display:none
clientWidth/clientHeight content + padding content + padding – 滚动条宽 0
offsetWidth/offsetHeight content + padding + border + 滚动条 content + padding + border 0
scrollWidth/scrollHeight content + padding + 溢出内容 content + padding + 溢出内容 0
style.height/style.width content + 滚动条宽 content + padding + border 前面两个之一
window.getComputedStyle content content + padding + border 前面两个之一

获取鼠标位置

属性 说明
clientX和clientY 相对于浏览器(可视区)的坐标,即浏览器左上角坐标的(0,0)
screenX和screenY 相对于屏幕左上角的坐标
offsetX和offsetY 相对于该事件源(当前元素)的位置
pageX和pageY 相对于整个文档(包括未显示区域)左上角的坐标

应用场景

  1. 使用offsetWidth和clientWidth计算滚动条宽度
  2. 判定元素是否滚动到底
    element.scrollHeight - element.scrollTop === element.clientHeight
    
  3. 获取页面滚动条当前位置
    //兼容写法
    if (document.documentElement && document.documentElement.scrollTop) { 
      scrollTop = document.documentElement.scrollTop; 
    } else if (document.body) {
      scrollTop = document.body.scrollTop; 
    }
    
  4. 获取页面可视范围高度
      // 不包含滚动条
    // width
    document.documentElement.clientWidth// height
    document.documentElement.clientHeight
    // 包含滚动条(ie9+, 不是css规范)
    // width
    window.innerWidth// height
    window.innerHeight
    
    //兼容写法
    let height = window.innerHeight ||  document.documentElement.clientHeight || document.body.clientHeight
    let width = window.innerWidth || document.documentElement.clientWidth   || document.body.clientWidth
    
  5. 判断页面滚动离开首屏

    js
    document.body.scrollTop > window.innerHeight

发表评论