最近在复习过程中看到了位置相关属性(即client、scroll、offset以及window中的几个位置值),发现这几个随时可能用的属性一直没记牢过。在网上搜索几篇文章看下来后却发现越来越迷糊,主要争论在clientHeight上:
- 一些说clientHeight是元素的可见高度
- 一些说clientHeight是元素的完整高度 本着实践出真知的原则,干脆自己动手研究,顺便记录分享
直接说结论
以下的content,指标准盒模型的content部分的宽度或高度(具体范围查看文末图示);
padding、border、滚动条,指各自的宽度(厚度),值不对称时将*2改为相加;
内容,指子元素的总渲染宽度或高度。
- client系列(均为只读)
clientHeight与clientWidthcontent + padding*2 - 滚动条 即盒模型border内矩形的宽高
clientLeft与clientTopborder [+ 滚动条] 即border的宽度。rtl模式下左边框挨着垂直滚动条,则需要加上滚动条
- scroll系列(scrollTop、scrollLeft可写)
scrollHeight与scrollWidthpadding*2 + 内容 - 滚动条 即border内的宽高,包括溢出不可见部分
scrollLeft与scrollTop值等于文档流起点方向上被滚动条隐藏的 内容+padding 大小 rtl模式下水平滚动条右边为起点0,滚动后scrollLeft为负值。也就是正常模式下,scrollLeft是被滚动隐藏的左边部分内容+padding;rtl模式下为右边部分被隐藏的内容+padding,且为负值
- offset系列(均为只读)
offsetParent指向最近包含该元素的定位元素或者最近的
table,td,th,body元素。当元素的style.display设置为none时,offsetParent返回nulloffsetHeight与offsetWidthborder*2 + padding*2 + content 即元素被完整撑开后的宽高
offsetLeft与offsetTop元素border外框线,到offsetParent的margin外框线的距离 offsetParent为null时,值为0
- window系列(均为只读)
innerHeight与innerWidth视口的宽高,包括滚动条
outerHeight与outerWidth整个浏览器的宽高,包括浏览器的菜单栏、标题栏等
scrollX(别名pageXOffset)与scrollY(别名pageYOffset)与scrollLeft、scrollTop相似,只是目标是整个窗口,且需要把margin计算在内 考虑兼容性,建议使用别名;rtl模式下同scroll系列一样为负值
- 行内元素的client系列与scroll系列值均为0,offset系列值正常计算
- 除了
scrollLeft、scrollTop在使用显示比例缩放的系统上可能会是一个小数,其他属性均为四舍五入的整数。
建议使用Element.getBoundingClientRect()获取位置属性,结果为相对于页面文档流起点方向的小数(MDN中说现代浏览器对于返回结果能够修改,但测试发现修改没有效果)
如果获取元素是否出现在页面中,还可以使用IntersectionObserver,更方便且性能更佳,在我另一篇文章里有相关介绍
比较有意思的点
- 无论是
content-box还是border-box,滚动条始终抢用content像素位置。padding在滚动条内侧,大小不变; - 浏览器计算位置数值会把被溢出隐藏的padding部分提到content盒子内计算(看下面的图)
- 谷歌浏览器滚动条默认17px,body的margin默认8px
浏览器开发者工具中显示的数值与上述属性得到的值一致,但页面显示中因为被滚动条挤压,content实际像素可能小于计算数值
box-sizing=content-box时,content等于width或height - 滚动条,开发者工具指示区域实际像素等于开发者工具显示数值;box-sizing=border-box时,content等于width - border*2 - padding*2 - 滚动条,开发者工具指示区域实际像素小于开发者工具显示数值。
box-sizing = content-box 时:
boxsizing = border-box 时: