使用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时,动画没有“起始状态”可以过渡。而我们现在的做法是:
- 先让元素以透明/偏移的状态存在于文档流中(或者先设置
display: block) - 再通过添加类触发动画,让元素从初始状态过渡到显示状态
- 隐藏时先执行动画,等动画结束后再设置
display: none
这样就能保证动画完整执行啦!
内容的提问来源于stack exchange,提问作者matt.mcg
相关产品推荐
相关产品推荐

