如何实现悬停时暂停动画、移出后继续完成的 CSS 交互效果-html教程

本文详解如何通过 javascript 精确控制 css 动画状态,实现元素悬停时正向旋转至 0° 并暂停,鼠标移出后平滑反向转回 -8° 的无缝交互动画。

在纯 CSS 中,:hover 触发的 transition 或 animation 无法真正“暂停”动画中间状态——一旦鼠标移出,过渡会立即反向或重置,导致视觉跳变(如原问题中“瞬间 snap 回 -8deg”)。要实现「悬停启动、完成停留、移出再反向还原」的自然效果,必须借助 JavaScript 主动管理动画生命周期与状态。

核心思路是:分离 hover 状态(用户交互)与动画状态(执行阶段),并通过 animationstart / animationend 事件精准同步二者,确保动画不被中断、不被覆盖、不丢失终点值。

✅ 正确实现步骤

1. 定义两套关键帧动画(无冗余前缀)

@keyframes rotate-forward {
  from { transform: rotate(-8deg); }
  to   { transform: rotate(0deg); }
}

@keyframes rotate-backward {
  from { transform: rotate(0deg); }
  to   { transform: rotate(-8deg); }
}

⚠️ 注意:@keyframes 名称需统一且语义清晰;现代浏览器无需 -webkit-/-ms- 前缀,CSS 自动兼容。

2. 初始化元素基础样式(含初始旋转)

.polaroid {
  width: 280px;
  height: 200px;
  padding: 10px 15px 100px 15px;
  border: 1px solid #bfbfbf;
  border-radius: 2%;
  background-color: white;
  box-shadow: 10px 10px 5px #aaaaaa;
  transform: rotate(-8deg); /* 初始态:-8deg */
  /* 不设 transition —— 全部由 animation 控制 */
}

3. 使用 JavaScript 状态机驱动动画

const ROTATE_FORWARD = 'rotate-forward';
const ROTATE_BACKWARD = 'rotate-backward';

// 四种互斥状态:backward(静止在-8°)、forward(静止在0°)、rotatingForward、rotatingBackward
const STATES = {
  backward: 'backward',
  forward: 'forward',
  rotatingForward: 'rotatingForward',
  rotatingBackward: 'rotatingBackward'
};

const elements = document.querySelectorAll('.polaroid');
const stateMap = new Map();

elements.forEach(el => {
  stateMap.set(el, STATES.backward); // 初始状态为 backward

  // 监听动画事件,更新状态
  el.addEventListener('animationstart', (e) => {
    if (e.animationName === ROTATE_FORWARD) {
      stateMap.set(el, STATES.rotatingForward);
    } else if (e.animationName === ROTATE_BACKWARD) {
      stateMap.set(el, STATES.rotatingBackward);
    }
    updateAnimation(el);
  });

  el.addEventListener('animationend', (e) => {
    if (e.animationName === ROTATE_FORWARD) {
      stateMap.set(el, STATES.forward);
    } else if (e.animationName === ROTATE_BACKWARD) {
      stateMap.set(el, STATES.backward);
    }
    updateAnimation(el);
  });

  // 监听鼠标事件,触发状态检查
  el.addEventListener('mouseenter', () => updateAnimation(el));
  el.addEventListener('mouseleave', () => updateAnimation(el));
});

function updateAnimation(el) {
  const isHovered = el.matches(':hover');
  const state = stateMap.get(el);

  // 仅在「静止态 + 状态变化」时启动新动画
  if (state === STATES.forward && !isHovered) {
    // 悬停结束 → 从 0° 转回 -8°
    el.style.animation = `${ROTATE_BACKWARD} 2s forwards`;
  } else if (state === STATES.backward && isHovered) {
    // 开始悬停 → 从 -8° 转到 0°
    el.style.animation = `${ROTATE_FORWARD} 2s forwards`;
  }
}

? 关键技术点说明:

  • forwards 填充模式:animation: name 2s forwards 确保动画结束后元素保持 to 关键帧的 transform 值(即 0° 或 -8°),避免样式回退;
  • 状态隔离:用 Map 为每个元素独立维护状态,支持多个 .polaroid 同时运行不同动画;
  • 防冲突机制:仅当元素处于 forward(已转到位)且 !isHovered,或 backward(初始位)且 isHovered 时才触发新动画,杜绝动画叠加或覆盖;
  • el.matches(‘:hover’):安全获取当前 hover 状态(比 mouseenter/leave 更可靠,尤其应对快速进出)。

? 可选增强:添加 CSS 类控制(更易维护)

若倾向使用 class 而非内联 style.animation,可改写 updateAnimation:

function updateAnimation(el) {
  const isHovered = el.matches(':hover');
  const state = stateMap.get(el);

  el.classList.remove('animating-forward', 'animating-backward');

  if (state === STATES.forward && !isHovered) {
    el.classList.add('animating-backward'); // 触发 .animating-backward { animation: ... }
  } else if (state === STATES.backward && isHovered) {
    el.classList.add('animating-forward');
  }
}

对应 CSS:

夏夕资源网专注于CMS网站模板,主流语言整站网站源码下载,网站建设相关教程分享,好用的软件素材整合下载,提供一站式便捷自助服务。
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,默认解压密码为"zy.lucklyus.top",如遇到无法解压的请联系管理员!
夏夕资源网-网站模板_免费源码_资源素材 » 如何实现悬停时暂停动画、移出后继续完成的 CSS 交互效果-html教程
在线时间:12:00 - 22:00
关注微信公众号:微信公众号
站长邮箱:[email protected]
  • 运营天数: 1393+
  • 资源总数: 47989+
  • 用户总数: 1+
  • 今日更新: 0+
  • 访问次数: 4022410+
  • 本周更新: 0+
  • 最后更新: 2026-03-16

本站指数

×
  • 运营天数: 1393+
  • 资源总数: 47989+
  • 用户总数: 1+
  • 今日更新: 0+
  • 访问次数: 4022410+
  • 本周更新: 0+
  • 最后更新: 2026-03-16