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

使用CSS动画与JavaScript实现Div显示隐藏切换

嘿,这个问题我熟!你现在的问题在于直接用display: none和display: block切换元素的时候,浏览器会立刻改变元素的可见状态,导致你的CSS动画根本没机会执行。咱们换个思路,用CSS类来控制动画触发,把样式和逻辑分开,这样就能完美实现点击按钮时的显示/隐藏动画了。

下面给你两种可行的方案,你可以根据需求选择:


方案一:基于你原有的Keyframes动画

首先调整你的CSS,把元素的初始隐藏状态和动画触发类分离开:

/* 默认隐藏状态,对应动画的起始帧 */
#reveal-content {
  opacity: 0;
  transform: translateZ(-1400px);
  display: none;
}

/* 显示时的动画类 */
#reveal-content.show {
  animation: slide-in-fwd-center 0.4s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}

/* 你原有的显示动画 */
@keyframes slide-in-fwd-center {
  0% { 
    transform: translateZ(-1400px); 
    opacity: 0; 
  }
  100% { 
    transform: translateZ(0); 
    opacity: 1; 
  }
}

/* 可选:添加隐藏时的反向动画 */
#reveal-content.hide {
  animation: slide-out-bck-center 0.4s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
}

@keyframes slide-out-bck-center {
  0% {
    transform: translateZ(0);
    opacity: 1;
  }
  100% {
    transform: translateZ(-1400px);
    opacity: 0;
  }
}

然后修改JavaScript逻辑,通过切换类来触发动画,并且在隐藏动画结束后再设置display: none(避免动画被打断):

const content = document.getElementById("reveal-content");
const revealBtn = document.getElementById("btn-reveal");

revealBtn.addEventListener('click', function() {
  if (content.style.display === "none") {
    // 先让元素进入DOM流,再触发显示动画
    content.style.display = "block";
    // 用requestAnimationFrame确保浏览器完成渲染后再添加类,保证动画生效
    requestAnimationFrame(() => {
      content.classList.add('show');
      content.classList.remove('hide');
    });
  } else {
    // 触发隐藏动画
    content.classList.add('hide');
    content.classList.remove('show');
    // 监听动画结束事件,完成后隐藏元素
    content.addEventListener('animationend', function handleAnimationEnd() {
      content.style.display = "none";
      // 移除监听,避免重复触发
      content.removeEventListener('animationend', handleAnimationEnd);
    });
  }
});

方案二:用CSS Transition(更简洁)

如果你不需要复杂的关键帧动画,用Transition也能实现同样的效果,代码更简洁:

#reveal-content {
  opacity: 0;
  transform: translateZ(-1400px);
  transition: all 0.4s cubic-bezier(0.250, 0.460, 0.450, 0.940);
  display: none;
}

#reveal-content.show {
  opacity: 1;
  transform: translateZ(0);
  display: block;
}

对应的JS逻辑:

const content = document.getElementById("reveal-content");
const revealBtn = document.getElementById("btn-reveal");

revealBtn.addEventListener('click', function() {
  if (content.style.display === "none") {
    content.style.display = "block";
    requestAnimationFrame(() => {
      content.classList.add('show');
    });
  } else {
    content.classList.remove('show');
    // 监听过渡结束后隐藏元素
    content.addEventListener('transitionend', function handleTransitionEnd() {
      content.style.display = "none";
      content.removeEventListener('transitionend', handleTransitionEnd);
    });
  }
});

核心原理说明

为什么原来的方法不行?因为display: none会让元素完全脱离文档流,浏览器不会为它计算渲染状态,直接切换到display: block时,动画没有“起始状态”可以过渡。而我们现在的做法是:

  1. 先让元素以透明/偏移的状态存在于文档流中(或者先设置display: block)
  2. 再通过添加类触发动画,让元素从初始状态过渡到显示状态
  3. 隐藏时先执行动画,等动画结束后再设置display: none

这样就能保证动画完整执行啦!

内容的提问来源于stack exchange,提问作者matt.mcg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:22:51