css - SVG 元素的反转动画

标签 css animation svg css-animations

我正在制作一个动画,该动画将在单击事件后使用 jQuery 添加一个类时触发。

它有一个类似开关的东西:

  1. 第一次点击按钮后,动画1将运行https://codepen.io/thijs-webber/pen/dMBKRp

  2. 第二次点击同一个按钮后需要运行反向动画

有没有办法轻松反转动画链?

.animation-container {
  width: 250px;
  position: relative;
  margin: 0 auto;
  margin-top: 50px;
}
.dot-pink-light {
  fill: #CE97AE;
}
.dot-pink {
  fill: #D82566;
}
.dot-green-light {
  fill: #AFBF99;
}
.dot-green {
  fill: #77BC1F;
}
/* ANIMATIONS */
@keyframes rotate_clockwise {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(45deg);
    transform: rotate(45deg);
  }
}
@keyframes rotate_anticlockwise {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(-90deg);
    transform: rotate(-90deg);
  }
}
@keyframes scale_down {
  0% {
    -webkit-transform: scale(1);
    transform: scale(1);
  }
  100% {
    -webkit-transform: scale(0.5);
    transform: scale(0.5);
  }
}
@keyframes pop_out_dots_top {
  100% {
    transform: translate(0px, -80px);
  }
}
@keyframes pop_out_dots_bottom {
  100% {
    transform: translate(0px, 80px);
  }
}
/* 1 */
.container.opened {
  animation: scale_down 250ms ease;
  transform-origin: 50% 50% 0;
}
/* 2 */
.container.opened .groups .extra-dot-top {
  animation: pop_out_dots_top 250ms ease;
  -webkit-animation-delay: 250ms;
  animation-delay: 250ms;
  transform-origin: 50% 50% 0;
}
.container.opened .groups .extra-dot-bottom {
  animation: pop_out_dots_bottom 250ms ease;
  -webkit-animation-delay: 250ms;
  animation-delay: 250ms;
  transform-origin: 50% 50% 0;
}
.container.opened .groups .group-2 {
  animation: rotate_anticlockwise 250ms ease;
  transform-origin: 50% 50% 0;
  -webkit-animation-delay: 250ms;
  animation-delay: 250ms;
}
/* 4 */
.container.opened .groups {
  animation: rotate_clockwise 250ms ease;
  transform-origin: 50% 50% 0;
  -webkit-animation-delay: 500ms;
  animation-delay: 500ms;
}
<div class="animation-container">
  <div class="col-xs-12">
    <?xml version="1.0" ?>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" enable-background="new 0 0 200 200">

      <!-- Group 1 -->
      <g class="container opened">
        <g class="groups">
          <g class="group-1 pink">
            <circle class="dot-pink-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-pink-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
            <circle class="dot-pink" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-pink" cx="100" cy="100" r="21.4" />
            <circle class="dot-pink" cx="100" cy="178.6" r="21.4" />
          </g>

          <!-- Group 2 -->
          <g class="group-2 green">
            <circle class="dot-green-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-green-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
            <circle class="dot-green" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-green" cx="100" cy="100" r="21.4" />
            <circle class="dot-green" cx="100" cy="178.6" r="21.4" />
          </g>
        </g>
      </g>
    </svg>
  </div>
</div>

最佳答案

由于您正在寻找仅具有两种不同状态的切换效果,因此使用过渡效果比使用动画效果要好得多。当类被移除时,过渡可以自动产生相反的效果。

带转换的演示:

window.onload = function() {
  var btn = document.querySelector('button');
  btn.addEventListener('click', function() {
    document.querySelector('.container').classList.toggle('opened');
  });
}
.animation-container {
  width: 250px;
  position: relative;
  margin: 0 auto;
  margin-top: 50px;
}
.dot-pink-light {
  fill: #CE97AE;
}
.dot-pink {
  fill: #D82566;
}
.dot-green-light {
  fill: #AFBF99;
}
.dot-green {
  fill: #77BC1F;
}
/* 1 */
.container {
  transform: scale(1);
  transition: transform 2.5s ease;
  transform-origin: 50% 50% 0;
  transition-delay: 5s;
}
.container.opened {
  transform: scale(0.5);
  transition-delay: 0s;
}

.container .groups .extra-dot-top {
  transform: translate(0px, 0px);
  transition: transform 2.5s ease;
  transition-delay: 2.5s;
  transform-origin: 50% 50% 0;
} 
.container.opened .groups .extra-dot-top {
  transform: translate(0px, -80px);
}
.container .groups .extra-dot-bottom {
  transform: translate(0px, 0px);
  transition: transform 2.5s ease;
  transition-delay: 2.5s;
  transform-origin: 50% 50% 0;
}
.container.opened .groups .extra-dot-bottom {
  transform: translate(0px, 80px);
}
.container .groups .group-2 {
  transform: rotate(0deg);
  transition: transform 2.5s ease;
  transform-origin: 50% 50% 0;
  transition-delay: 2.5s;
}
.container.opened .groups .group-2 {
  transform: rotate(-90deg);
}
/* 4 */
.container .groups {
  transform: rotate(0deg);
  transition: transform 2.5s ease;
  transform-origin: 50% 50% 0;
}
.container.opened .groups {
  transform: rotate(45deg);
  transition-delay: 5s;
}
<div class="animation-container">
  <div class="col-xs-12">
    <?xml version="1.0" ?>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" enable-background="new 0 0 200 200">

      <!-- Group 1 -->
      <g class="container">
        <g class="groups">
          <g class="group-1 pink">
            <circle class="dot-pink-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-pink-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
            <circle class="dot-pink" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-pink" cx="100" cy="100" r="21.4" />
            <circle class="dot-pink" cx="100" cy="178.6" r="21.4" />
          </g>

          <!-- Group 2 -->
          <g class="group-2 green">
            <circle class="dot-green-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-green-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
            <circle class="dot-green" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-green" cx="100" cy="100" r="21.4" />
            <circle class="dot-green" cx="100" cy="178.6" r="21.4" />
          </g>
        </g>
      </g>
    </svg>
  </div>
</div>
<button>Click</button>


而动画不能自动产生反转效果,需要写代码。即使编写了反向动画的代码,让它工作也很复杂(并且不能使用纯 CSS 完成),因为您必须在添加“关闭”动画之前删除“打开”动画,并且当元素发生时在执行反向效果之前将立即捕捉到它们的原始位置。除非您输入大量困惑的代码,否则输出不会像转换那样优雅。

带动画的演示:

window.onload = function() {
  var btn = document.querySelector('button');
  var container = document.querySelector('.container');
  var groups = document.querySelector('.groups');
  var group2 = document.querySelector('.group-2');
  var extradtG = document.querySelector('.green .extra-dot-top');
  var extradtP = document.querySelector('.pink .extra-dot-top');
  var extradbG = document.querySelector('.green .extra-dot-bottom');
  var extradbP = document.querySelector('.pink .extra-dot-bottom');
  var opened = false;
  btn.addEventListener('click', function() {
    if (opened) {
      container.style.transform = 'scale(1)';
      extradtG.style.transform = 'translate( 0px, 0px)';
      extradtP.style.transform = 'translate( 0px, 0px)';
      extradbG.style.transform = 'translate( 0px, 0px)';
      extradbP.style.transform = 'translate( 0px, 0px)';
      group2.style.transform = 'rotate(0deg);'
      groups.style.transform = 'rotate(0deg)';
      container.classList.remove('opened');
      container.clientHeight; // dummy call
      container.classList.add('closed');
    } else {
      container.style.transform = 'scale(0.5)';
      extradtG.style.transform = 'translate( 0px, -80px)';
      extradtP.style.transform = 'translate( 0px, -80px)';
      extradbG.style.transform = 'translate( 0px, 80px)';
      extradbP.style.transform = 'translate( 0px, 80px)';
      group2.style.transform = 'rotate(-90deg);'
      groups.style.transform = 'rotate(45deg)';
      container.classList.remove('closed');
      container.clientHeight; // dummy call
      container.classList.add('opened');
    }
    opened = !opened;
  });
}
.animation-container {
  width: 250px;
  position: relative;
  margin: 0 auto;
  margin-top: 50px;
}
.dot-pink-light {
  fill: #CE97AE;
}
.dot-pink {
  fill: #D82566;
}
.dot-green-light {
  fill: #AFBF99;
}
.dot-green {
  fill: #77BC1F;
}
/* ANIMATIONS */

@keyframes rotate_clockwise {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(45deg);
  }
}
@keyframes rotate_anticlockwise {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(-90deg);
  }
}
@keyframes scale_down {
  0% {
    transform: scale(1);
  }
  100% {
    transform: scale(0.5);
  }
}
@keyframes pop_out_dots_top {
  0% {
    transform: translate(0px, 0px);
  }
  100% {
    transform: translate(0px, -80px);
  }
}
@keyframes pop_out_dots_bottom {
  0% {
    transform: translate(0px, 0px);
  }
  100% {
    transform: translate(0px, 80px);
  }
}
/* 1 */

.container.opened {
  animation: scale_down 2.5s ease;
  transform-origin: 50% 50% 0;
}
.container.closed {
  animation: scale_down 2.5s ease reverse backwards;
  transform-origin: 50% 50% 0;
  animation-delay: 5s;
}
/* 2 */

.container.opened .groups .extra-dot-top {
  animation: pop_out_dots_top 2.5s ease backwards;
  animation-delay: 2.5s;
  transform-origin: 50% 50% 0;
}
.container.closed .groups .extra-dot-top {
  animation: pop_out_dots_top 2.5s ease reverse backwards;
  animation-delay: 2.5s;
  transform-origin: 50% 50% 0;
}
.container.opened .groups .extra-dot-bottom {
  animation: pop_out_dots_bottom 2.5s ease backwards;
  animation-delay: 2.5s;
  transform-origin: 50% 50% 0;
}
.container.closed .groups .extra-dot-bottom {
  animation: pop_out_dots_bottom 2.5s ease reverse backwards;
  animation-delay: 2.5s;
  transform-origin: 50% 50% 0;
}
.container.opened .groups .group-2 {
  animation: rotate_anticlockwise 2.5s ease backwards;
  transform-origin: 50% 50% 0;
  animation-delay: 2.5s;
}
.container.closed .groups .group-2 {
  animation: rotate_anticlockwise 2.5s ease reverse backwards;
  transform-origin: 50% 50% 0;
  animation-delay: 2.5s;
}
/* 4 */

.container.opened .groups {
  animation: rotate_clockwise 2.5s ease backwards;
  transform-origin: 50% 50% 0;
  animation-delay: 5s;
}
.container.closed .groups {
  animation: rotate_clockwise 2.5s ease reverse backwards;
  transform-origin: 50% 50% 0;
}
<div class="animation-container">
  <div class="col-xs-12">
    <?xml version="1.0" ?>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" enable-background="new 0 0 200 200">

      <!-- Group 1 -->
      <g class="container">
        <g class="groups">
          <g class="group-1 pink">
            <circle class="dot-pink-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-pink-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
            <circle class="dot-pink" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-pink" cx="100" cy="100" r="21.4" />
            <circle class="dot-pink" cx="100" cy="178.6" r="21.4" />
          </g>

          <!-- Group 2 -->
          <g class="group-2 green">
            <circle class="dot-green-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-green-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
            <circle class="dot-green" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-green" cx="100" cy="100" r="21.4" />
            <circle class="dot-green" cx="100" cy="178.6" r="21.4" />
          </g>
        </g>
      </g>
    </svg>
  </div>
</div>
<button>Click</button>

(动画版本有一个虚拟调用 container.clientHeight 这样做是为了确保在移除一个动画和添加另一个动画之间进行重绘。否则,它会看起来好像什么都没发生。您可以在我的回答中找到更多详细信息 here)

关于css - SVG 元素的反转动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37346935/

相关文章:

悬停时带有 Logo 的 CSS 背景图片

css - 从 CSS3 动画 SVG 创建动画 gif

ios - 如何用图像创建侧滚动条效果?

javascript - Snap.js - 如何将属性设置为加载的 svg

internet-explorer - 剪辑矩形区域旋转 raphael.js

javascript - 将 CSS 应用于当前页面链接不起作用

javascript - 在 Zepto 动画函数中使用变量

html - 如何使用 HTML/CSS 对列表 "backwards"进行排序,以便列表从右到左、自下而上填充?

javascript - 试图让函数与 window.onload 循环但不起作用

javascript - 使用 rafael.js 拖动圆圈 - 代码示例