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

如何消除汉堡菜单点击按钮与动画执行间的延迟?

汉堡菜单隐藏动画延迟问题解决方法

你的问题核心在于硬编码setTimeout时长和直接切换display: none的时机不当,导致隐藏动画看起来有延迟。下面给出两种优化方案,彻底解决这个问题:

方案一:用CSS过渡代替动画(推荐)

过渡比@keyframes更简洁可控,不需要写反向动画逻辑:

修改后的CSS:

.header__menu{
    position: absolute;
    left: 0;
    top: 2.6em;
    flex-direction: column;
    width: 100vw;
    color: #fff;
    text-transform: lowercase;
    @include concert-one;
    font-size: 1.8rem;
    background-color: $violet;
    text-align: center;
    overflow: hidden;
    display: none;
    max-height: 0;
    /* 用过渡实现展开/收起动画 */
    transition: max-height 1s ease-in;
}

/* 激活状态:显示菜单并展开 */
.header__menu.active {
    display: flex;
    max-height: 100vh;
}

修改后的JS:

// 初始状态
hamburgerMenu.classList.remove('active');
hamburgerMenu.style.display = 'none';

hamburgerButton.addEventListener('click', () => {
    const isHidden = hamburgerMenu.style.display === 'none';
    
    if (isHidden) {
        hamburgerMenu.style.display = 'flex';
        // 强制浏览器重绘,确保过渡触发
        void hamburgerMenu.offsetWidth;
        hamburgerMenu.classList.add('active');
    } else {
        hamburgerMenu.classList.remove('active');
        // 监听过渡结束后再隐藏
        hamburgerMenu.addEventListener('transitionend', function handler() {
            hamburgerMenu.style.display = 'none';
            hamburgerMenu.removeEventListener('transitionend', handler);
        }, { once: true });
    }
});

方案二:保留动画,监听动画结束事件

如果坚持使用@keyframes,不要用setTimeout,而是监听animationend事件精准触发隐藏:

修改后的CSS:

/* 合并展开/收起动画为一个,用reverse反向播放 */
@keyframes menuToggle {
    from { max-height: 0; }
    to { max-height: 100vh; }
}

.header__menu{
    position: absolute;
    left: 0;
    top: 2.6em;
    flex-direction: column;
    width: 100vw;
    color: #fff;
    text-transform: lowercase;
    @include concert-one;
    font-size: 1.8rem;
    background-color: $violet;
    text-align: center;
    overflow: hidden;
    display: none;
}

.header__menu.appear {
    display: flex;
    animation: menuToggle 1s ease-in forwards;
}

.header__menu.hide {
    animation: menuToggle 1s ease-in reverse forwards;
}

修改后的JS:

// 初始状态
hamburgerMenu.classList.remove('appear', 'hide');
hamburgerMenu.style.display = 'none';

hamburgerButton.addEventListener('click', () => {
    const isHidden = hamburgerMenu.style.display === 'none';
    
    if (isHidden) {
        hamburgerMenu.classList.remove('hide');
        hamburgerMenu.style.display = 'flex';
        void hamburgerMenu.offsetWidth;
        hamburgerMenu.classList.add('appear');
    } else {
        hamburgerMenu.classList.remove('appear');
        hamburgerMenu.classList.add('hide');
        // 动画结束后隐藏,避免硬编码时长
        hamburgerMenu.addEventListener('animationend', function handler() {
            hamburgerMenu.style.display = 'none';
            hamburgerMenu.removeEventListener('animationend', handler);
        }, { once: true });
    }
});

关键优化点说明

  1. 摒弃setTimeout:浏览器的setTimeout受主线程任务影响,计时并不精准,监听transitionend/animationend事件才能准确捕捉动画结束时机。
  2. 强制重绘:void hamburgerMenu.offsetWidth会触发浏览器重排,确保状态变化被识别,避免动画不触发的问题。
  3. 用类切换代替直接操作style:更符合CSS与JS分离的原则,代码更易维护。

内容的提问来源于stack exchange,提问作者cryon234

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:54:51