不使用void和setTimeout实现点击按钮后重启CSS动画
原理解析
浏览器会合并同一执行上下文内的所有DOM样式修改操作,你先移除.fade类再立刻添加回去的操作会被浏览器判定为最终状态无变化,因此不会触发动画重放。void theBody.offsetWidth属于hack实现,作用是强制浏览器同步完成样式计算和布局重排,先提交移除类的状态变更,再添加类时才能检测到状态变化触发动画。
以下是不需要offsetWidth读取、也不用setTimeout的替代方案:
方案1:使用Web Animations API(最优方案)
直接用标准JS动画API控制动画执行,不需要依赖类切换和重排hack,每次调用都会重新触发动画,可控性更强。
修改后的JS代码:
function showHome() { const theActive = document.querySelector(".with-curtain.active"); const theHides = document.querySelectorAll(".hide"); const theBody = document.querySelector("body"); theActive.classList.remove("active"); theHides.forEach(function (removeHide) { removeHide.classList.remove("hide"); }); // 移除旧类避免冲突 theBody.classList.remove("fade"); // 直接执行动画,参数和原有CSS动画完全对齐 theBody.animate([ { opacity: 0 }, { opacity: 1 } ], { duration: 2000, easing: 'ease', fill: 'forwards' }); }
你也可以保留原有CSS的@keyframes fade定义,直接通过动画名称调用:
theBody.animate('fade', { duration: 2000, easing: 'ease', fill: 'forwards' });
方案2:双requestAnimationFrame实现
适合不想改动现有CSS动画定义的场景,通过帧回调确保类移除的状态被浏览器提交后再重新添加类,完全无hack。
修改后的JS代码:
function showHome() { const theActive = document.querySelector(".with-curtain.active"); const theHides = document.querySelectorAll(".hide"); const theBody = document.querySelector("body"); theActive.classList.remove("active"); theHides.forEach(function (removeHide) { removeHide.classList.remove("hide"); }); theBody.classList.remove("fade"); // 两次requestAnimationFrame确保类移除的状态已被浏览器处理 requestAnimationFrame(() => { requestAnimationFrame(() => { theBody.classList.add("fade"); }); }); }
方案3:读取计算样式强制刷新队列
和原有逻辑最接近,改动最小,读取非布局属性只会触发样式计算,不会触发重排,性能远高于读取offsetWidth。
修改后的JS代码:
function showHome() { const theActive = document.querySelector(".with-curtain.active"); const theHides = document.querySelectorAll(".hide"); const theBody = document.querySelector("body"); theActive.classList.remove("active"); theHides.forEach(function (removeHide) { removeHide.classList.remove("hide"); }); theBody.classList.remove("fade"); // 读取非布局样式属性,强制浏览器刷新样式队列 getComputedStyle(theBody).opacity; theBody.classList.add("fade"); }
内容的提问来源于stack exchange,提问作者user16776772
相关产品推荐
相关产品推荐

