CSS Keyframe动画切换异常:复用同名关键帧为何失效?
问题描述
有一个矩形元素,点击按钮切换animation-in和animation-out类来实现淡入淡出的缩放动画。原本使用两个内容完全一致、仅名称不同的关键帧(scale-easeInOutBounce和scale-easeInOutBounce-out)时,动画运行正常;但将.animation-out的animation-name改为和.animation-in相同的scale-easeInOutBounce后,动画完全失效,点击按钮时元素直接跳变状态,没有过渡动画。该问题在Windows 11的Chrome浏览器中可复现。
失效代码如下:
<!DOCTYPE html> <html> <head> <title>Rectangle Animation</title> <style> #myRectangle { width: 100px; height: 150px; background-color: green; margin: 20px; transform: scale(0); } .animation-out { animation-duration: 4s; animation-timing-function: ease; animation-delay: 0s; animation-iteration-count: 1; animation-direction: normal; animation-fill-mode: forwards; animation-play-state: running; animation-name: scale-easeInOutBounce; animation-timeline: auto; animation-range-start: normal; animation-range-end: normal; } .animation-in { animation-duration: 4s; animation-timing-function: ease; animation-delay: 0s; animation-iteration-count: 1; animation-direction: reverse; animation-fill-mode: forwards; animation-play-state: running; animation-name: scale-easeInOutBounce; animation-timeline: auto; animation-range-start: normal; animation-range-end: normal; } @keyframes scale-easeInOutBounce { 0% { transform: scale(1); } 2% { transform: scale(0.99); } 4% { transform: scale(1); } 10% { transform: scale(0.97); } 14% { transform: scale(0.99); } 22% { transform: scale(0.88); } 32% { transform: scale(0.99); } 42% { transform: scale(0.6); } 50% { transform: scale(0.5); } 58% { transform: scale(0.4); } 68% { transform: scale(0.01); } 78% { transform: scale(0.12); } 86% { transform: scale(0.01); } 90% { transform: scale(0.03); } 96% { transform: scale(0); } 98% { transform: scale(0.01); } 100% { transform: scale(0); } } </style> </head> <body> <div id="myRectangle"></div> <button id="toggleButton">Toggle Animation</button> <script> document.getElementById('toggleButton').addEventListener('click', function() { var rectangle = document.getElementById('myRectangle'); if (rectangle.classList.contains('animation-in')) { rectangle.classList.remove('animation-in'); rectangle.classList.add('animation-out'); } else { rectangle.classList.remove('animation-out'); rectangle.classList.add('animation-in'); } }); </script> </body> </html>
原因分析
核心问题在于CSS动画的状态复用机制:
- 当元素应用过某个名称的动画并完成后,浏览器会保留该动画的状态(标记为“已完成”)。
- 后续如果仅修改该动画的其他属性(如
animation-direction)但保持animation-name不变,浏览器不会重新触发动画,而是直接应用新属性对应的最终状态,跳过过渡过程。 - 原来使用不同关键帧名称时,每次切换类都是给元素应用一个全新的动画名称,浏览器会重新初始化并执行动画,因此能正常显示过渡效果;改成同一名称后,切换类时动画名称未变,浏览器认为无需重新执行动画,导致动画失效。
解决方案
要解决这个问题,需要强制浏览器重新初始化动画,常用方法是在切换类时先移除所有动画类,让浏览器完成重绘后再添加新类:
修改JavaScript代码如下:
document.getElementById('toggleButton').addEventListener('click', function() { var rectangle = document.getElementById('myRectangle'); const hasInClass = rectangle.classList.contains('animation-in'); // 先移除所有动画类 rectangle.classList.remove('animation-in', 'animation-out'); // 利用setTimeout让浏览器完成重绘后再添加新类 setTimeout(() => { if (hasInClass) { rectangle.classList.add('animation-out'); } else { rectangle.classList.add('animation-in'); } }, 0); });
这样每次切换时,元素会先回到无动画的初始状态,再应用新的动画类,浏览器会重新触发动画,恢复正常的过渡效果。
内容的提问来源于stack exchange,提问作者GrumpyDog
相关产品推荐
相关产品推荐

