本文分析 JavaScript 运动动画中常见的 OffsetWidth 计算 Bug。当元素设置边框时,OffsetWidth 包含边框宽度,直接赋值会导致元素反向增大。通过封装 getStyle 函数获取纯 CSS 宽度并减去数值,可修复该问题,确保动画按预期缩小。
OffsetWidth Bug 的产生原因
首先,我们来探讨这个 Bug 是如何产生的。
具体代码如下:
<style type="text/css">
#div1 {
width: 200px;
height: 200px;
background: red;
}
</style>
HTML 结构代码如下:
<body>
<div id="div1">
</div>
</body>
接下来是用于测试的 JavaScript 代码,其目的是让 div 元素逐渐变窄。
实现代码如下:
<script type="text/javascript">
setInterval(function(){
var oDiv=document.getElementById("div1");
oDiv.style.width=oDiv.offsetWidth-1+'px';
},30);
</script>
这段 JavaScript 代码逻辑简单,运行后没有任何报错,div 元素如愿以偿地逐渐变小。
那么,这个 Offset 相关的 Bug 究竟是如何出现的呢?
接下来,如果我们修改一下样式,神奇的现象就会发生。
我们给 div1 添加一个边框样式:border: 1px solid #CCCCFF;。
修改后的样式代码如下:
<style type="text/css">
#div1 {
width: 200px;
height: 200px;
background: red;
border: 1px solid #CCCCFF;
}
</style>
此时再次运行代码,会发现 div 元素竟然向右逐渐增大。图片展示了这一 Bug 现象:明明是减去 1px,为什么会出现这种情况?
我们需要思考 Offset 属性的特点:
举例来说,如果 div 的 width 为 200px,且 border 为 1px,那么实际获取的 offsetWidth 将是 202px。
回到运动过程,刚开始时,div 的 width 是 200px,但 offsetWidth 是 202px。
此时执行 oDiv.style.width=oDiv.offsetWidth-1+'px'; 这句话,实际上等同于 oDiv.style.width=202-1=201px; 然后将这个值赋给 width。
当再次执行这句话时,div 的 width 变成了 201px。由于 offsetWidth 仍然包含边框,每次计算都会增加 1px,导致元素反而慢慢变大。这就是 Offset 带来的 Bug。
解决方案:获取纯 CSS 宽度
如何解决这个问题呢?
其实,不使用 offsetWidth 即可解决。我们可以直接使用 width 属性,编写一个函数来直接获取 CSS 样式中的 width 值。
以下是获取非行间样式的代码:
具体实现如下:
function getStyle(obj, name) {
if (obj.currentStyle) {
return obj.currentStyle[name];
} else {
return getComputedStyle(obj, null)[name];
}
}
接下来,我们修改原来的运动代码:
修改后的脚本代码如下:
<script type="text/javascript">
setInterval(function(){
var oDiv=document.getElementById("div1");
oDiv.style.width=parseInt(getStyle(oDiv,'width'))-1+'px';
},30);
function getStyle(obj, name) {
if (obj.currentStyle) {
return obj.currentStyle[name];
} else {
return getComputedStyle(obj, null)[name];
}
}
</script>这样修改后,程序运行就不会再出现任何问题。