更快完成CSS动画

q0qdq0h2  于 2022-12-20  发布在  其他
关注(0)|答案(1)|浏览(134)

我有一个带有CSS关键帧动画的沙漏CSS元素。动画可以无限长时间工作;在每次迭代结束时,它旋转到起始位置并继续工作。
我需要重新启动动画上的按钮点击。但不是立即重新启动,而是加快它非常快的开始位置,然后开始正常工作了。
我试着点击改变动画的样式-持续时间I迭代计数,但随后动画立即停止。并在结束动画事件使其正常工作,但它从最后一个位置开始。

const hourglass = document.querySelector(".hourglass")
const before = document.querySelector(".before")
const after = document.querySelector(".after")

const button = document.querySelector('button');

const handleClick = ()=>{
    hourglass.style.animationDuration = '1s';
  hourglass.style.animationIterationCount = 1
  
    before.style.animationDuration = '1s';
  before.style.animationIterationCount = 1
  
    after.style.animationDuration = '1s';
  after.style.animationIterationCount = 1
}

button.addEventListener('click',handleClick);

  hourglass.addEventListener('animationend', (event) => {
    setTimeout(()=>{
        hourglass.style.animationDuration = '8s';
  hourglass.style.animationIterationCount = "infinite";
  
    before.style.animationDuration = '8s';
  before.style.animationIterationCount = "infinite";
  
    after.style.animationDuration = '8s';
  after.style.animationIterationCount = "infinite";
    },1000)
    
  });
*
{
  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;
}
.hourglass, .hourglass .before, .hourglass .after
{
  animation-duration: 4s;
  animation-iteration-count: infinite; 
}

.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;
  }
<div class="hourglass">
  <div class="before"></div>
  <div class="after"></div>
</div>

<button >Click</button>
xxe27gdn

xxe27gdn1#

你解决的问题是,当你改变动画的持续时间,如果休息时间比你的新持续时间短,它会立即停止。所以我激活和删除动画,并在javascript中启动它,并在它启动时花费时间。我们不需要在初始时这样做,因为我们可以在eventstart上使用事件侦听器,但在每隔一个迭代,我们将需要这样做。所以我只是重用这段代码,而不是创建一个新代码。
点击的时候,我把那一刻的时间和开始的时间比较一下,这个时间意味着动画在那一刻之前工作了多长时间,加上250毫秒,动画就会在那一刻完成。
之后,我们需要再次重置动画,这样它就会从头开始,而不是旧的位置。

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

const button = document.querySelector("button");

// Initial
const resetAnimation = () => {
  hourglass.style.animationName = "none";
  before.style.animationName = "none";
  after.style.animationName = "none";
};

resetAnimation();

let time;
let disableClick = false;

const activeAnimation = () => {
  disableClick = false;

  const speed = "8000ms";
  time = +new Date();

  hourglass.style.animationName = "";
  before.style.animationName = "";
  after.style.animationName = "";

  hourglass.style.animationDuration = speed;
  before.style.animationDuration = speed;
  after.style.animationDuration = speed;
};

activeAnimation();

const handleClick = () => {
  if (disableClick) return;

  disableClick = true;

  const newTime = +new Date();

  const speed = newTime - time + 250;

  hourglass.style.animationDuration = speed + "ms";
  before.style.animationDuration = speed + "ms";
  after.style.animationDuration = speed + "ms";
};

button.addEventListener("click", handleClick);

hourglass.addEventListener("animationiteration", (event) => {
  resetAnimation();

  setTimeout(() => {
    activeAnimation();
  }, 100);
});
* {
  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;
}
.hourglass,
.hourglass .before,
.hourglass .after {
  animation-duration: 8000ms;
  animation-iteration-count: infinite;
}

.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;
}
<div class="hourglass">
      <div class="before"></div>
      <div class="after"></div>
    </div>

    <button>Click</button>

相关问题