You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

不使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 20:45:03