如何避免div取消悬停时缩放动画出现卡顿或突兀效果?
解决Div悬停/取消悬停时的动画跳变问题
你的代码核心问题是混用了transition和animation,且hover状态直接设置静态scale值,导致鼠标移入/移出时,元素会先跳转到静态值再执行动画,破坏流畅性。此外初始的shrink动画未定义0%关键帧,也会导致初始状态衔接异常。
下面给出两种可行的解决方案:
方案一:纯CSS优化版
通过调整关键帧的起始/结束状态,移除冲突的transition和静态scale设置,让动画直接衔接元素的当前状态:
* { box-sizing: border-box; margin: 0; } body { height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } .container { margin: 10px; height: 60vh; width: 70vw; background-color: antiquewhite; /* 初始状态由shrink动画的forwards保持 */ animation: shrink 0.45s ease-in-out 1 forwards; } .container:hover { /* 覆盖原有动画,播放弹跳放大动画并保持最终状态 */ animation: stretch 1.5s ease-in-out 1 forwards; } @keyframes stretch { 0% { scale: 0.7; } /* 匹配初始缩放状态 */ 20% { scale: 1; } 40% { scale: 0.9; } 60% { scale: 1; } 80% { scale: 0.95; } 100% { scale: 1; } } @keyframes shrink { 0% { scale: 1; } /* 匹配hover后的最终状态 */ 20% { scale: 0.9; } 100% { scale: 0.7; } }
注意:如果鼠标在弹跳动画未结束时快速移出,此方案仍会有轻微跳变(因为CSS无法实时获取元素当前缩放值),如果需要完全无缝衔接,推荐方案二。
方案二:JavaScript辅助版
通过JS实时获取元素当前的缩放比例,动态设置动画的起始值,实现完全流畅的衔接:
CSS代码
* { box-sizing: border-box; margin: 0; } body { height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } .container { margin: 10px; height: 60vh; width: 70vw; background-color: antiquewhite; transform: scale(0.7); /* 初始缩放状态 */ } /* 使用CSS变量定义动画的起始缩放值 */ @keyframes stretch { 0% { transform: scale(var(--start-scale)); } 20% { transform: scale(1); } 40% { transform: scale(0.9); } 60% { transform: scale(1); } 80% { transform: scale(0.95); } 100% { transform: scale(1); } } @keyframes shrink { 0% { transform: scale(var(--start-scale)); } 20% { transform: scale(0.9); } 100% { transform: scale(0.7); } } /* 动画触发类 */ .bounce-in { animation: stretch 1.5s ease-in-out 1 forwards; } .bounce-out { animation: shrink 0.45s ease-in-out 1 forwards; }
JavaScript代码
const container = document.querySelector('.container'); // 获取元素当前的缩放比例 function getCurrentScale(element) { const transform = window.getComputedStyle(element).transform; if (transform === 'none') return 1; const matrix = new DOMMatrix(transform); return matrix.a; // 等比缩放时,x/y轴缩放值一致 } // 鼠标移入触发弹跳放大 container.addEventListener('mouseenter', () => { container.classList.remove('bounce-out'); container.style.setProperty('--start-scale', getCurrentScale(container)); container.classList.add('bounce-in'); }); // 鼠标移出触发弹跳缩小 container.addEventListener('mouseleave', () => { container.classList.remove('bounce-in'); container.style.setProperty('--start-scale', getCurrentScale(container)); container.classList.add('bounce-out'); }); // 动画结束后清除类,避免重复触发冲突 container.addEventListener('animationend', () => { container.classList.remove('bounce-in', 'bounce-out'); });
此方案无论鼠标何时移入/移出,动画都会从元素当前的缩放状态开始,完全消除跳变问题。
内容的提问来源于stack exchange,提问作者Aryan Srivastava
相关产品推荐
相关产品推荐

