CSS3动画钟摆效果

时间:2015-12-07 14:59:08

标签: html css css3 css-animations

我想用纯CSS制作钟摆效果,但它并不顺畅。

这是我想要的,但纯CSS。 http://www.webdevdoor.com/demos/html5-pendulum-demo/

但我更喜欢根据它的位置看起来更像自然的速度变化。

Fiddle



.bellImg {
  height: 20px;
  width: 20px;
  position: absolute;
  right: 10px;
  top: 18px;
  -webkit-animation-name: rotate;
  animation-delay: 3s;
  -webkit-animation-duration: 2s;
  -webkit-animation-iteration-count: infinite;
  -webkit-animation-direction: linear;
  -webkit-transform-origin: 50% 0%;
  -webkit-animation-timing-function: ease-in-out;
}
@-webkit-keyframes rotate {
  0% {
    -webkit-transform: rotate(0deg);
  }
  10% {
    -webkit-transform: rotate(10deg);
  }
  20% {
    -webkit-transform: rotate(20deg);
  }
  30% {
    -webkit-transform: rotate(10deg);
  }
  40% {
    -webkit-transform: rotate(5deg);
  }
  50% {
    -webkit-transform: rotate(0deg);
  }
  60% {
    -webkit-transform: rotate(-5deg);
  }
  70% {
    -webkit-transform: rotate(-10deg);
  }
  80% {
    -webkit-transform: rotate(-20deg);
  }
  90% {
    -webkit-transform: rotate(-10deg);
  }
  100% {
    -webkit-transform: rotate(0deg);
  }
}

<img class="bellImg" src="img/bell.png">
&#13;
&#13;
&#13;

3 个答案:

答案 0 :(得分:7)

您的代码中存在一些问题:

  • animation-timing-function指定为ease-in-out。这表示动画开始和结束缓慢,但两者之间的速度更快。为了优雅平等的移动,应将其设置为linear

      

    这就是MDN says about ease-in-out timing function

         

    此关键字表示计时函数cubic-bezier(0.42,0.0,0.58,1.0)。使用此计时功能,动画开始缓慢,加速然后在接近其最终状态时减速。一开始,它的行为类似于轻松入功能;最后,它类似于缓出功能。

  • animation-direction没有名为linear的值。
  • 分裂不相等。也就是说,对于大约10%的间隙,它旋转10度,而对于其他间隙,它仅旋转5度。使分裂相等。

以下完成所有更正的片段会产生平滑的动画。

&#13;
&#13;
.bellImg {
  height: 20px;
  width: 20px;
  position: absolute;
  right: 10px;
  top: 18px;
  -webkit-animation-name: rotate;
  animation-delay: 3s;
  -webkit-animation-duration: 2s;
  -webkit-animation-iteration-count: infinite;
  -webkit-animation-direction: normal;
  -webkit-transform-origin: 50% 0%;
  -webkit-animation-timing-function: linear;  /* or make your custom easing */
}
@-webkit-keyframes rotate {
  0% {
    -webkit-transform: rotate(0deg);
  }
  25% {
    -webkit-transform: rotate(20deg);
  }
  75% {
    -webkit-transform: rotate(-20deg);
  }
  100% {
    -webkit-transform: rotate(0deg);
  }
}
&#13;
<img class="bellImg" src="https://cdn1.iconfinder.com/data/icons/freeline/32/bell_sound_notification_remind_reminder_ring_ringing_schedule-48.png">
&#13;
&#13;
&#13;

将动画的速度设置为依赖于位置(即,当它达到极限并在中间加速时减速)是不可能用纯CSS实现的(即使我们添加额外的元素)

根据位置设置动画的速度,一个选项是执行以下操作:

  • 将图像添加到容器元素中。对其进行动画处理,使其从20deg旋转到-40deg。
  • 使父动画的开始时间早于动画持续时间的1/3 rd 。也就是说,通过0.66s减少父亲的延迟。这样做是为了让父母偏移孩子的初始轮换。差异是动画持续时间的1/3 rd ,因为它是父母到0deg所花费的时间。
  • 更改图像动画的关键帧,使旋转范围为-20deg至40deg。
  • animation-direction设置为alternate,使它们在第一次迭代时向前进,向下进行反向,依此类推。
  • animation-timing-function设置为ease-in-out,以便在接近极值时减慢速度。当动画持续时间增加时,效果会更明显。

&#13;
&#13;
.container {
  position: absolute;
  height: 20px;
  width: 20px;
  /* right: 10px; commented for demo */
  top: 18px;
  transform: rotate(20deg);
  animation-name: rotate-container;
  animation-delay: 2.33s;
  animation-duration: 2s;
  animation-iteration-count: infinite;
  animation-direction: alternate;
  transform-origin: 50% 0%;
  animation-timing-function: ease-in-out;
}
.bellImg {
  height: 100%;
  width: 100%;  
  transform: rotate(-20deg);
  animation-name: rotate;
  animation-delay: 3s;
  animation-duration: 2s;
  animation-iteration-count: infinite;
  animation-direction: alternate;
  transform-origin: 50% 0%;
  animation-timing-function: ease-in-out;
}
@keyframes rotate {
  0% {
    transform: rotate(-20deg);
  }
  100% {
    transform: rotate(40deg);
  }
}
@keyframes rotate-container {
  0% {
    transform: rotate(20deg);
  }
  100% {
    transform: rotate(-40deg);
  }
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='container'>
  <img class="bellImg" src="https://cdn1.iconfinder.com/data/icons/freeline/32/bell_sound_notification_remind_reminder_ring_ringing_schedule-48.png">
</div>
&#13;
&#13;
&#13;

仅在代码段中使用了无前缀库,以避免使用浏览器前缀。

答案 1 :(得分:4)

摆锤运动所涉及的等式是正弦运动。

您可以使用以下动画获得此动作

.base {
  height: 600px;
  width: 10px;
  position: absolute;
  animation: base 10s infinite linear;
  background-color: lightgray;
  transform: translateX(588px);
}

@keyframes base {
  from {transform: translateX(77px);}
  to {transform: translateX(760px);}
}

.element {
  height: 10px;
  width: 10px;
  background-color: green;
  border-radius: 100%;
  animation: element 10s infinite;
  transform: translateY(553px);
}

@keyframes element {
  from {transform: translateY(294px); animation-timing-function: ease-out;}
  25% {transform: translateY(36px); animation-timing-function: ease-in;}
  50% {transform: translateY(294px); animation-timing-function: ease-out;}
  75% {transform: translateY(553px); animation-timing-function: ease-in;}
  to {transform: translateY(294px);}
}

.ref {
  width: 800px;
  height: 600px;
  background-image: url(http://i.stack.imgur.com/Fx4bR.png);
  background-size: cover;
}
<div class="base">
<div class="element">
</div>
</div>
<div class="ref"></div>

我不得不使用一些手工值来调整背景图像,但关键的想法是在计时功能中。

如果预设功能不是您想要的,您可以设置立方贝塞尔曲线并根据需要进行调整。

.base {
  height: 600px;
  width: 10px;
  position: absolute;
  animation: base 10s infinite linear;
  background-color: lightgray;
  transform: translateX(588px);
}

@keyframes base {
  from {transform: translateX(77px);}
  to {transform: translateX(760px);}
}

.element {
  height: 10px;
  width: 10px;
  background-color: green;
  border-radius: 100%;
  animation: element 10s infinite;
  transform: translateY(553px);
}

@keyframes element {
  from {transform: translateY(294px); 
        animation-timing-function: cubic-bezier(0.1, 0.3, 0.3, 1);}
  25% {transform: translateY(36px); 
        animation-timing-function: cubic-bezier(0.7, 0.0, 0.9, 0.7);}
  50% {transform: translateY(294px); 
        animation-timing-function: cubic-bezier(0.1, 0.3, 0.3, 1);}
  75% {transform: translateY(553px); 
        animation-timing-function: cubic-bezier(0.7, 0.0, 0.9, 0.7);}
  to {transform: translateY(294px);}
}

.ref {
  width: 800px;
  height: 600px;
  background-image: url(http://i.stack.imgur.com/Fx4bR.png);
  background-size: cover;
}
<div class="base">
<div class="element">
</div>
</div>
<div class="ref"></div>

这是用于参考的图像

grafic for reference

这将是应用于钟摆的2个计时功能

.test {
  height: 400px;
  width: 10px;
  background-color: lightgreen;
  display: inline-block;
  margin: 10px 100px;
  transform-origin: center top;
}

.anim1 {
   animation: oscil1 6s infinite; 
}

.anim2 {
   animation: oscil2 6s infinite; 
}


@keyframes oscil1 {
  from {transform: rotate(0deg); animation-timing-function: cubic-bezier(0.1, 0.3, 0.3, 1);}
  25% {transform: rotate(20deg); animation-timing-function: cubic-bezier(0.7, 0.0, 0.9, 0.7);}
  50% {transform: rotate(0deg); animation-timing-function: cubic-bezier(0.1, 0.3, 0.3, 1);}
  75% {transform: rotate(-20deg); animation-timing-function: cubic-bezier(0.7, 0.0, 0.9, 0.7);}
  to {transform: rotate(0deg);}
}

@keyframes oscil2 {
  from {transform: rotate(0deg); animation-timing-function: ease-out;}
  25% {transform: rotate(20deg); animation-timing-function: ease-in;}
  50% {transform: rotate(0deg); animation-timing-function: ease-out;}
  75% {transform: rotate(-20deg); animation-timing-function: ease-in;}
  to {transform: rotate(0deg);}
}
<div class="test anim1"></div>
<div class="test anim2"></div>

答案 2 :(得分:0)

我这里没有使用CSS,但是因为(似乎)你只想避免,我已经在原生JS中实现了它。它使用Math.sin()方法平滑地补间值。如您所见,效果非常流畅,只需要很少的代码。

var img = document.querySelector( '.bellImg' ),
    start = 0;
function sine(){
  img.style.transform = "rotate(" + 20 * Math.sin( start ) + "deg)";
  start += 0.05;
  setTimeout(sine, 1000/30)
}
setTimeout( sine, 3000 );
.bellImg {
  height: 20px;
  width: 20px;
  position: absolute;
  left: 10px;
  top: 18px;
}
<img class="bellImg" src="https://cdn1.iconfinder.com/data/icons/freeline/32/bell_sound_notification_remind_reminder_ring_ringing_schedule-48.png">

希望这有帮助!