CSS3 Animated Pendulum Effect

I want a pendulum effect with pure CSS, but it is not smooth.

Here is what I want, but with pure CSS. http://www.webdevdoor.com/demos/html5-pendulum-demo/

But I prefer to look more like a natural change in speed depending on its position.

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">
Run codeHide result
+4
source share
3 answers

There are several problems in the code:

  • animation-timing-functionindicated as ease-in-out. This means that the animation starts and ends slowly, but there is more speed between them. For a graceful and even movement, this should be set to linear.

    , MDN :

    - (0,42, 0,0, 0,58, 1,0). , . ; , .

  • linear animation-direction.
  • . , 10% - 10 , 5 . .

.

.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);
  }
}
<img class="bellImg" src="https://cdn1.iconfinder.com/data/icons/freeline/32/bell_sound_notification_remind_reminder_ring_ringing_schedule-48.png">
Hide result

, ( , ), CSS ( )p > .

:

  • . , 20deg -40deg.
  • , , 1/3 rd . 0.66s. , . 1/3 rd , , 0deg.
  • , -20deg 40deg.
  • animation-direction alternate , , ..
  • animation-timing-function ease-in-out, . , .

.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);
  }
}
<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>
Hide result

, .

+6

, , .

.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>
Hide result

, .

, , .

.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>
Hide result

,

grafic for reference

,

.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>
Hide result
+3

I did not use CSS here, but since (it seems) you just want to avoid libraries, I implemented it in native JS. It uses a method Math.sin()to reproduce values ​​uniformly. As you can see, the effect is very smooth and requires very little code.

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">
Run codeHide result

Hope this helps!

0
source

Source: https://habr.com/ru/post/1618909/


All Articles