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

如何快速加速CSS沙漏动画至初始状态后重启?

问题描述

我制作了一个带有CSS关键帧动画的沙漏元素,动画默认无限循环,每次迭代结束后旋转回初始位置继续运行。现在需要实现点击按钮时,不立即重启动画,而是快速加速至初始位置,之后恢复正常动画速度继续循环。

我尝试点击时修改animation-duration和animation-iteration-count属性,但动画会立即停止;且在animationend事件中恢复无限循环设置时,动画会从最后位置开始,达不到预期效果。

解决方案

核心思路是通过类切换控制动画状态,避免直接修改内联样式导致的动画中断,同时保证快速复位后能无缝衔接正常循环。

实现要点

  1. 拆分动画状态为两个CSS类:
    • .normal-loop:保留原动画的无限循环和正常时长
    • .fast-reset:设置短时长和单次迭代,用于快速完成剩余动画回到初始位置
  2. 点击按钮时,切换元素的动画类,触发快速复位流程
  3. 监听animationend事件,复位完成后切回正常循环类,恢复无限动画
完整代码

HTML

<div class="hourglass normal-loop">
  <div class="before normal-loop"></div>
  <div class="after normal-loop"></div>
</div>

<button>快速复位</button>

CSS

*
{
  border: 0;
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
:root
{
  --bg:#e3e4e8;
  --fg:#2e3138;
  --primary:#255ff4;
  font-size: calc(16px + (24 - 16) *(100vw - 320px) / (1280 - 320));
}
body
{
  display: grid;
  font:1em/1.5 sans-serif;
  height: 100vh;
  place-items:center;
}
/* 正常循环动画类 */
.normal-loop {
  animation-duration: 4s;
  animation-iteration-count: infinite;
}
/* 快速复位动画类 */
.fast-reset {
  animation-duration: 0.5s;
  animation-iteration-count: 1;
  animation-timing-function: linear;
}

.hourglass {
  --polygonH: polygon(0% 0%,100% 0%,100% 5.55%,95% 5.55%,95% 28%,60%
   46%,60% 54%,95% 72%,95% 94.45%,100% 94.45%,100% 100%,0% 100%,0% 94.45%,5% 94.45%,5% 72%,40% 54%,40% 46%,5% 28%,5% 5.55%,0% 5.55%);
  animation-name: flip;
  animation-timing-function: ease-in-out;
  background-image: linear-gradient(var(--primary) 0.5em, #737a8c55 0.5em 8.5em, var(--primary) 8.5em);
  clip-path: var(--polygonH);
  -webkit-clip-path: var(--polygonH);
  overflow: hidden;
  position: relative;
  width: 5em;
  height: 9em;
  z-index: 0;
}
.hourglass .before, .hourglass .after
{
  animation-timing-function: linear;
  content: "";
  display: block;
  position: absolute;
}
.hourglass .before {
  --polygonB1: polygon(0% 0%,100% 0%,100% 24%,50% 47%,50% 47%,50% 47%,50% 47%,50% 47%,50% 47%,50% 47%,50% 47%,0% 24%);
  --polygonB2: polygon(0% 4%,100% 4%,100% 24%,55% 45%,55% 100%,55% 100%,55% 100%,45% 100%,45% 100%,45% 100%,45% 45%,0% 24%);
  --polygonB3: polygon(0% 24%,100% 24%,100% 24%,55% 45%,55% 80%,100% 100%,100% 100%,0% 100%,0% 100%,45% 80%,45% 45%,0% 24%);
  --polygonB4: polygon(45% 45%,55% 45%,55% 45%,55% 45%,55% 58%,100% 76%,100% 100%,0% 100%,0% 76%,45% 58%,45% 45%,45% 45%);
  --polygonB5: polygon(50% 53%,50% 53%,50% 53%,50% 53%,50% 53%,100% 76%,100% 100%,0% 100%,0% 76%,50% 53%,50% 53%,50% 53%);
  animation-name: fill;
  background: var(--fg);
  background-size: 100% 3.6em;
  clip-path: var(--polygonB1);
  top: 0.5em;
  left: 0.5em;
  width: 4em;
  height: 8em;
  z-index: 1;
}
.hourglass .after {
  animation-name: glare;
  background:
    linear-gradient(90deg,#0000 0.5em,#0003 0.5em 1.5em,#0000 1.5em 3.5em,#fff3 3.5em 4.5em,#fff0 4.5em 6.5em,#0003 6.5em 7.5em,#0000 7.5em) 0 0 / 100% 0.5em,
    linear-gradient(90deg,#0000 0.75em,#0003 0.75em 1.25em,#0000 1.25em 3.75em,#fff3 3.75em 4.25em,#fff0 4.25em 6.75em,#0003 6.75em 7.25em,#0000 7.25em) 0 0.5em / 100% 8em,
    linear-gradient(90deg,#0000 0.5em,#0003 0.5em 1.5em,#0000 1.5em 3.5em,#fff3 3.5em 4.5em,#fff0 4.5em 6.5em,#0003 6.5em 7.5em,#0000 7.5em) 0 100% / 100% 0.5em;
    background-repeat: repeat-x;
    top: 0;
    left: -3em;
    width: 200%;
    height: 100%;
    z-index: 2;
  }
  @keyframes fill{
    from{
      clip-path: var(--polygonB1);
      -webkit-clip-path:var(--polygonB1);
    }
    10%{
      clip-path: var(--polygonB2);
      -webkit-clip-path:var(--polygonB2);
    }
    45%{
      clip-path: var(--polygonB3);
      -webkit-clip-path:var(--polygonB3);
    }
    80%{
      clip-path: var(--polygonB4);
      -webkit-clip-path:var(--polygonB4);
    }
    85%, to{
      clip-path: var(--polygonB5);
      -webkit-clip-path:var(--polygonB5);
    }
  }
  @keyframes glare{
    from, 90%
    {
      transform: translateX(0);
    }
    to
    {
      transform: translateX(3em);
    }
  }
  @keyframes flip{
    from, 90%
    {
      transform: rotate(0);
    }
    to{
      transform: rotate(180deg);
    }
  }
  
  button{
    padding: 5px 15px;
    border: 1px solid gray;
    margin-top: 2em;
  }

JavaScript

const hourglass = document.querySelector(".hourglass");
const before = document.querySelector(".before");
const after = document.querySelector(".after");
const button = document.querySelector('button');

const resetElements = [hourglass, before, after];

const handleClick = () => {
  // 切换到快速复位动画
  resetElements.forEach(el => {
    el.classList.remove('normal-loop');
    el.classList.add('fast-reset');
    // 强制重绘,确保动画触发
    void el.offsetWidth;
  });
};

const handleAnimationEnd = (event) => {
  // 仅处理快速复位动画的结束事件
  if (event.target.classList.contains('fast-reset')) {
    resetElements.forEach(el => {
      el.classList.remove('fast-reset');
      el.classList.add('normal-loop');
      // 强制重绘,恢复正常循环
      void el.offsetWidth;
    });
  }
};

button.addEventListener('click', handleClick);
// 给所有动画元素绑定结束事件
resetElements.forEach(el => {
  el.addEventListener('animationend', handleAnimationEnd);
});

内容的提问来源于stack exchange,提问作者Boombaar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 10:05:30