CSS 动画每 n 秒重复一次

CSS animation to repeat every nth second

我正在为一个 svg 元素制作动画,目前如下所示

.r1 {
     transform-box: fill-box;
     transform-origin: 50% 50%;    
     animation-name: simpleRotation,xRotation;
     animation-delay: 0s, 2s;
     animation-duration: 2s;
     animation-iteration-count: 1, 1;
     animation-timing-function: linear;
     animation-direction: normal;
     animation-fill-mode: forwards;
}

@keyframes simpleRotation {
     from {
         transform: rotate(0deg); 
    }
     to {
         transform: rotate(359deg);
  
    }
}
@keyframes xRotation {
     from {
         transform: rotateX(0deg); 
    }
     to {
         transform: rotateX(359deg); 
    }
}
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
<rect class="r1" id="r1" x="10" y="10" width="10" height="10" stroke="black" stroke-width="0.25" fill="orange"></rect>    
    </svg>

是否可以将动画(使用 javascript)以某种方式排队,以便动画每 2 秒一个接一个地循环运行,例如 simpleRotation(0-2s);xRotation(2-4s);simpleRotation(4-6s);xRotation(6-8s);simpleRotation(8-10s);.....

在这种情况下,SVG animation 格式比 CSS 关键帧动画更易于使用 - 原则上。

SVG 动画可以定义与事件相关的动画开始时间 - 其中包括另一个动画的结束时间。这样您就可以将动画链接在一起,并且可以定义循环:

<animate id="first" begin="0s;second.end" ... />
<animate id="second" begin="first.end" ... />

第一个动画开始于0s,另外由第二个动画结束触发,第二个动画由第一个动画结束触发。

您的用例的问题是您想要为 3D 变换函数设置动画。 SVG transform 在语法上不同于 CSS transform,并且只支持 2D 转换。所以下面的例子最多只能模拟一下效果,很多细节还得另写。

<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
  <rect id="r1" x="-5" y="-5" transform="translate(15 15)"
        width="10" height="10" stroke="black" stroke-width="0.25" fill="orange">
    <animateTransform id="simpleRotation" attributeName="transform" type="rotate"
                      additive="sum" begin="0s;xRotation.end" dur="2s"
                      from="0" to="360" />
    <animateTransform id="xRotation" attributeName="transform" type="scale"
                      additive="sum" begin="simpleRotation.end" dur="2s"
                      values="1 1;1 -1;1 1" keyTimes="0;0.5;1"
                      calcMode="spline" keySplines=".375 0 .375 1;.375 0 .375 1" />
  </rect>
</svg>

  • 动画对象的中心最初放置在 0,0 以简化以下变换。每个 <animateTransform> 都有一个 additive="sum" 属性,因此它是 post-multiplied 到动画对象上的静态 translate() 属性。
  • 为了模拟 xRotate(),使用 scale 变换将 y 轴从 1 缩放到 -1 并返回。此外,还定义了样条插值以提供平滑“旋转”的印象。请注意,此模拟仅在没有 perspective.
  • 的情况下有效

的替代方法可能是使用网络动画 API

关键帧动画可以翻译成这样的动画对象

let ani1 = animEl.animate(
  [{
    transform: "rotate(0deg)"
  }, {
    transform: "rotate(359deg)"
  }], {
    delay: 500,
    duration: 1000,
    iterations: 1
  }
);

另请参阅:MDN: Using the Web Animations API

例子

let animEl = document.querySelector(".rect1");

let ani1 = animEl.animate(
  [{
    transform: "rotate(0deg)"
  }, {
    transform: "rotate(359deg)"
  }], {
    delay: 500,
    duration: 1000,
    iterations: 1
  }
);

let ani2 = animEl.animate(
  [{
    transform: "rotateX(0deg)"
  }, {
    transform: "rotateX(359deg)"
  }], {
    delay: 500,
    duration: 1000,
    iterations: 1,
  }
);
// pause 2. animation
ani2.pause();

// chain animations
ani1.onfinish = function() {
  ani2.play();
};

ani2.onfinish = function() {
  ani1.play();
};
svg {
  border: 1px solid #ccc;
  display: block;
  width: 10em
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
  <rect class="rect1" id="r1" x="25" y="25" width="50" height="50" stroke="black" stroke-width="0.25" fill="orange" transform-origin="50 50" ></rect>
</svg>

我们通过

暂停第二个开始动画
 ani2.pause();

并添加一个 eventListener 以在第一个动画完成后启动第二个动画。

ani1.onfinish = function() {
  ani2.play();
};

编辑你也可以使用premises as described by Dan Wilson

不要错过 svg 的 SMIL 动画的强大功能

特别是当涉及到 svg 相关动画时,他们仍然提供许多在 css 动画中不可用的花里胡哨的东西,例如

  1. 连续动画:

    <动画[...] begin="firstAnimation.end" />

通过 begin 属性 启动连续动画(无需计算之前的持续时间)的能力真是太棒了——这个优雅的概念应该被应用到相应的 css 动画中方法。

  1. 沿路径移动元素
  2. 自包含动画——比如加载微调器 ... svg 获胜!

犬:

SMIL animations tend to have more solid browser support than Web Animations API
虽然,由于 Internet Explorer 的感激退休,它可以忽略不计。