JS中clientHeight、scrollHeight和offsetHeight的大坑,滚动条抖动问题解决
1.什么是clientHeight、scrollHeight和offsetHeight
学习原生js的人一定会接触到client家族、scroll家族和offset家族。其中clienHeight、scrollHeight和offsetHeight一般用来求网页内容的高度,而对应的clientWidth、scrollWidth和offsetWidth则用来求网页内容的宽度,由于width和Height属性是类似的,所以这里我只挑这三个height来讲一下。
1.1 clientHeight是什么
clientHeight很多文章把它翻译成网页的可见高度,实际上是不太准确的,首先,从单词本身来说,client并没有可见的意思,(client 顾客,客户,委托人)。其次,clientHeight获取到的高度其实和内容可不可见没有一点关系。下面给出我的结论:
clientHeight = (content height) + (padding top+padding bottom);
翻译成中文就是 clientHeight = 内容实际高度 + 上下内边距。
而内容实际高度可以用window.getComputeStyle(obj).height或者$(obj).css(“height”)获取。
简单的来说:在网页的盒子模型中,一个元素由内到外分别由 height + padding + border + margin组成,而clientHeight只取前面的height和padding。不管内容可不可见,即使你用定位把元素移出屏幕外,clientHeight获取到的值仍然不变。
1.2 offsetHeight是什么
单词offset意为补偿,抵消,而offsetHeight也很简单,关于offsetHeight网上并没有太多争议,这里直接给出我的结论
offsetHeight = height + padding + border.
即在clientHeight的基础上加上了上下border的高度。
同样的offsetHeight获取到的高度是网页实际渲染出来的高度+内边距+边框。和元素本身是否可见无关。
1.3 clientHeight和offsetHeight的注意点
- 当元素设置为display:none;之后,clientHeight和offsetHeight的高度均变为0,因为浏览器不会对display:none的元素进行渲染,所以使用时一定要注意这一点.
- 当父元素没有明确高度时,clientHeight和offsetHeight计算高度时,不会计算设置了绝对定位或者固定定位的元素的宽高,只会对子元素中的标准流元素和清除了浮动的浮动元素高度进行累加得到父元素的实际高度。(这一点有别于我接下来要说的scrollHeight)
1.4 scrollHeight和它的大坑
scrollHeight有的人翻译成可滚动内容的高度,这个翻译还是比较准确的,但是网上大部分人都没有讲清楚scrollHeight到底是什么。这里我给出我的结论。
- scrollHeight和元素本身的高度完全无关,是浏览器根据元素padding和子元素的盒模型高度累加计算出来的。
- scrollHeight计算高度时,会累加上以自身为定位祖先元素的所有后代定位元素的可视高度。
什么意思呢,让我们来看一个例子:
可以看到,在用scrollHeight获取可滚动内容的高度时有这么一个坑,那就是当你不希望定位的后代元素被计算入滚动总高度的时候,使用scrollHeight将导致出现比较大的错误。
这个问题我也是这两天封装一个滚动条组件的时候才遇到的。本来想着用盒子的scrollHeight去获取内容的高度,但是却导致了滚动条的抖动问题,原因是我让定位的后代元素随着滚动高度而改变位置和高度,导致scrollHeight获取到值发生改变,频繁地触发滚动条的刷新,导致抖动。解决办法:
1.如果是自己封装的滚动条组件,则不要使用scrollHeight获取内容高度,改用非定位子元素的offsetHeight累加来计算得出内容高度;
2.如果是采用默认的浏览器滚动条如overflow : auto;则想办法让不希望计入滚动高度的元素分离出来,例如用position:fixed代替positon:absolute;或者把它移除结构外。
jQuery和原生js获取高度的方式对比:
设要获取的元素为obj,另外此处的获取方法只针对box-sizing:content-box;对于box-sizing:border-box;暂时没有测试。有兴趣的小伙伴可以自己去试一下。
1.只想获取内容实际高度的(只有height ,不包括padding、border、margin)
原生js: window.getComputeStyle(obj).height----------- jQuery: $ (obj).css(“height”)或$(obj).height();
2.只想获取height+padding.
原生js: obj.clientHeight---------- jQuery: $ (obj).innerHeight();
3.只想获取height+padding+border
原生js: obj.offsetHeight--------------- jQuery: $ (obj).outerHeight();
4.想获取height+padding +border +margin
原生js: 暂无-------------jQuery: $ (obj).outerHeight(true);
</div>
<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-e44c3c0e64.css" rel="stylesheet">
</div>