- A+
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
最近遇到一个问题,计算滚动距离,滚动比例达到某界定值时,显示mask,很常见吧^ _ ^
这里讲的不是这个需求的实现,是其中遇到了一个比较有意思的bug,靠这个bug才达到了正确效果,以及这个bug是如何暴露的(很重要
)。
下面是演示代码和动图
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .container { width: 300px; max-height: 300px; background-color: black; position: absolute; top: 60px; left: 50%; transform: translateX(-50%); overflow-y: auto; } .child { width: 260px; height: 600px; margin: 0px 20px; background-color: pink; position: relative; } .flag { position: absolute; width: 100%; height: 25px; background-color: blueviolet; color: aliceblue; text-align: center; line-height: 25px; font-size: 14px; left: 0; right: 0; } .top { top: 0; } .bottom { bottom: 0px; } </style> </head> <body> <div class="container"> <div class="child"> <div class="flag top">top</div> <div class="flag bottom">bottom</div> </div> </div> </body> </html>
开始计算啦,公式:滚动比例
= 滚动距离
/ 可滚动距离
滚动距离
: $0.scrollTop
可滚动距离
: $0.scrollHeight - $0.offsetHeight
即:scrollRatio = scrollTop / (scrollHeight - offsetHeight)
滚动到底部,计算结果是 300 / (600 - 300) = 1
我们需要拿scrollRatio
和某界定值(比如0.1)
作大小的比较,计算是true
还是false
(用isShow = scrollRatio < 某界定值
来保存)。
这里一切正常。
不正常的情况出现了
就是没有出现滚动条的情况,即.child
的高度没有超过.container
的高度时,把.child
的高度设成.container
的max-height
,就没有滚动条了(下面讲的情景也都是没有滚动条的情况)。
这个时候再去计算,得到了NaN,以至于 NaN < 0.1 = false
。
因为isShow
的预期就是false
,所以一直都没有发现这个bug。
那么它是如何暴露的呢?
后来新的需求给.container
加了border。演示一下加border,然后再去计算:
发现没,这时候$0.offsetHeight
的高度把border的高度也算进去了,结果就成了true
,这不是想要的结果 ❌。
然后就是一番查验
offsetHeight
是一个元素的总高度,包括可见内容的高度、内边距(padding)、滚动条的高度(如果存在)以及边框(border)的高度。
而我们这里只需要可见的高度,就可以用到另一个属性了clientHeight
。
clientHeight
是指元素的可见内容区域的高度,不包括滚动条的高度和边框的高度。它仅包括元素的内部空间,即内容加上内边距。
当然这也只是继续使除数为0,然后得到结果为NaN,不过bug已经暴露出来了,后面就是一些其他的优化啦~
总结 + 复习(盒模型 box-sizing)
发现没有,offsetHeight
和clientHeight
的区别,就像盒模型
中的标准盒模型
和怪异盒模型
的区别:
box-sizing: content-box
(默认,标准盒模型):宽度和高度的计算值都 不包含 内容的边框(border)和内边距(padding)。添加padding和border时, 会 使整个div的宽高变大。
box-sizing: border-box
(怪异盒模型):宽度和高度的计算值都 包含 内容的边框(border)和内边距(padding)。添加padding和border时, 不会 使整个div的宽高变大。