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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 17:15:06