CSS :not(:hover) 触发关键帧动画异常问题求助
问题::not(:hover)触发的动画仅能正常恢复一次,后续异常
使用:not(:hover)触发的元素恢复动画仅能正常工作一次,之后会出现异常(如下方动图所示),尝试寻找:hover反向效果的替代方案但未找到合适的,求解决建议。
.expanding-button { width: 7rem; height: 7rem; background-color: blue; color: white; border-radius: 50%; cursor: pointer; transition: all 0.5s ease-in-out; } .button__img { width: 5rem; height: auto; transition: all 1s ease-in-out; } .expanding-button:hover .button__img { animation-delay: 1s; animation: spin 1s forwards, move-left 1s forwards; transform-origin: center left; } .expanding-button:hover { background-color: darkblue; width: 700px; height: 100px; border-radius: 50px; } .expanding-button:not(:hover) .button__img { animation: move-right 0.5s forwards; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes move-left { 0% { transform: translateX(0); } 100% { transform: translateX(-18rem); } } @keyframes move-right { 0% { transform: translateX(-18rem); } 100% { transform: translateX(0); } }

解决方案
问题根源
动画设置了forwards属性,执行后元素会固定在动画的最后一帧状态。当再次触发:not(:hover)时,move-right动画的起始帧(0%)是硬编码的translateX(-18rem),但此时元素的实际状态可能已经偏离这个值,导致动画执行逻辑混乱。另外,hover时同时应用了spin和move-left两个动画,它们的transform属性会叠加,离开hover时仅用move-right无法重置旋转状态,这也是异常的原因之一。
方案一:用transition替代动画(推荐)
放弃使用@keyframes动画,改用transition结合CSS变量来控制状态切换,这种方式更稳定,也更符合CSS状态切换的逻辑:
.expanding-button { width: 7rem; height: 7rem; background-color: blue; color: white; border-radius: 50%; cursor: pointer; transition: all 0.5s ease-in-out; } .button__img { width: 5rem; height: auto; transform-origin: center left; /* 用CSS变量定义状态 */ --rotate: 0deg; --translate: 0; /* hover时延迟1s执行动画,离开时无延迟 */ transition: transform 1s ease-in-out 1s, transform 0.5s ease-in-out; transform: rotate(var(--rotate)) translateX(var(--translate)); } .expanding-button:hover { background-color: darkblue; width: 700px; height: 100px; border-radius: 50px; } .expanding-button:hover .button__img { --rotate: 360deg; --translate: -18rem; } .expanding-button:not(:hover) .button__img { --rotate: 0deg; --translate: 0; }
方案二:重置动画状态(适合必须用动画的场景)
如果一定要保留@keyframes动画,可以通过JavaScript强制重置动画状态。核心思路是在鼠标离开时,先移除动画类,强制浏览器重绘后再重新添加,让动画从头开始执行:
<div class="expanding-button" id="expandBtn"> <img class="button__img" src="你的图片路径" alt="按钮图标"> </div>
/* 保留基础样式和原动画,调整触发逻辑 */ .expanding-button:hover .button__img { animation-delay: 1s; animation: spin 1s forwards, move-left 1s forwards; transform-origin: center left; } /* 新增重置动画,同时处理旋转和位移 */ .expanding-button:not(:hover) .button__img.reset { animation: spin-back 0.5s forwards, move-right 0.5s forwards; } @keyframes spin-back { 0% { transform: rotate(360deg); } 100% { transform: rotate(0deg); } } /* 原动画保持不变 */ @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes move-left { 0% { transform: translateX(0); } 100% { transform: translateX(-18rem); } } @keyframes move-right { 0% { transform: translateX(-18rem); } 100% { transform: translateX(0); } }
const expandBtn = document.getElementById('expandBtn'); const btnImg = expandBtn.querySelector('.button__img'); expandBtn.addEventListener('mouseleave', () => { // 先移除重置类 btnImg.classList.remove('reset'); // 强制浏览器重绘,确保动画能重新触发 void btnImg.offsetWidth; // 添加重置类,执行恢复动画 btnImg.classList.add('reset'); });
内容的提问来源于stack exchange,提问作者DevJelle
相关产品推荐
相关产品推荐

