Smooth element animation swing via CSS Transform

Asked

Viewed 1,750 times

9

The concept being sought is the continuous motion on the X axis between a value and its negative representation:

Gráfico com onda de efeito desejado

So far, this concept has a flaw, the animation is performed from 0 degrees to the given value, but then when going back to the same value in negative, there is a jump to 0 degrees and only then animates to the given value. The same happens when returning to the positive value:

Gráfico com onda do efeito problemático

See example in Jsfiddle

$.fn.animateRotate = function(angle, duration, easing, complete) {
  var args = $.speed(duration, easing, complete);
  var step = args.step;
  return this.each(function(i, e) {
	args.complete = $.proxy(args.complete, e);
	args.step = function(now) {
	  $.style(e, 'transform', 'rotate(' + now + 'deg)');
	  if (step) return step.apply(e, arguments);
	};

	$({deg: 0}).animate({deg: angle}, args);
  });
};

// animate snowman
var d = 5;

function jingle() {
  $("#snowman").animateRotate(d, {
    duration: 1337,
    easing: 'linear',
    complete: function () {
      jingle(d = -d);
    }
  });
}

jingle();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<img id="snowman" alt="snowman" src="http://i.stack.imgur.com/AmNNj.png">

The object to animate

The image below is the object you want to animate as you can analyze in the demonstrations.

Snowman, who else?

Question

How can I smooth the effect to get to the desired animation curve?

3 answers

7

Using @keyframes along with the property animation to have control over the animation.

Keyframes on the MDN

Animations on MDN


For this case, only with CSS, a possible solution would be:

@-webkit-keyframes snowman {
    from {-webkit-transform: rotate(4deg)}
    to   {-webkit-transform: rotate(-4deg)}
}

@keyframes snowman {
    from {transform: rotate(4deg)}
    to   {transform: rotate(-4deg)}
}

#snowman {
    -webkit-animation: snowman 2s alternate infinite ease-in-out;
            animation: snowman 2s alternate infinite ease-in-out;
}
<img id="snowman" alt="snowman" src="http://i.stack.imgur.com/AmNNj.png">

6


One suggestion is to trust this animation to CSS, via transition of transform: rotate().

I think jQuery can be simplified to:

var ang = -5;
var el = document.querySelector('img');

setInterval(function () {
    ang = -ang;
    el.style[prefix + 'transform'] = 'rotate(' + ang + 'deg)';
}, 1000);

and the CSS

img {
    -moz-transition: all 1s ease-in-out;
    -webkit-transition: all 1s ease-in-out;
    -o-transition: all 1s ease-in-out;
    transition: all 1s ease-in-out;
}

and adding a patch for browsers that need suffixes can be used

var prefix = (function () {
    var styles = window.getComputedStyle(document.documentElement, ''),
        pre = (Array.prototype.slice.call(styles)
            .join('')
            .match(/-(moz|webkit|ms)-/) || (styles.OLink === '' && ['', 'o']))[1];
    if (pre == 'moz') return '';
    return '-' + pre + '-';
})();

(adapted / imported from David Walsh’s blog)

Then the excitement would be: http://jsfiddle.net/k4fp79w1/

4

Forgetting a little bit about the code part, let’s think about the following:

  • When a rounded object resting on the ground rotates, it also moves to the side corresponding to the turn.

  • Moreover, the shadow does not rotate together, but rather projects according to the shape of the object. In this case, the shadow is a "generic stain", because it is a drawing only, but it is expected to move according to the object.


Starting from that, I divided the doll in question into two images: The One, and the Shadow.

As already answered by @Renan (who also received my upvote), keyframes are an interesting path for this type of animation, as they will usually be managed by a subsystem separate from the browser, probably in a thread separate from the JS, ensuring a more fluid animation, while at the same time less overloading the main application (but note the "note 2" at the bottom of the question, to see the points against).


Putting all this together follows the result (the vendor-prefix gets in the way of elegance a little):

@-webkit-keyframes snowman { from { -webkit-transform: translateX(-20px) rotate(-10deg) }
                             to   { -webkit-transform: translateX( 20px) rotate( 10deg) } }
@-webkit-keyframes shadow  { from { -webkit-transform: translateX(-10px) }
                             to   { -webkit-transform: translateX( 10px) } }
@keyframes snowman         { from { transform: translateX(-20px) rotate(-10deg) }
                             to   { transform: translateX( 20px) rotate(  0deg) } }
@keyframes shadow          { from { transform: translateX(-10px) }
                             to   { transform: translateX( 10px) } }
#snowman { -webkit-animation: snowman 2s alternate infinite ease-in-out;
                   animation: snowman 2s alternate infinite ease-in-out; z-index:10; }
#shadow  { -webkit-animation: shadow  2s alternate infinite ease-in-out;
                   animation: shadow  2s alternate infinite ease-in-out; z-index: 0; }
#boneco { min-height: 350px } #boneco img { position: absolute; }
<p>Aumente a janela ou use a barra de rolagem para ver o efeito.</p>
<div id="boneco">
  <img id="snowman" src="http://i.stack.imgur.com/GRMcV.png">
  <img id="shadow"  src="http://i.stack.imgur.com/ZDz9I.png">
</div>

Note 1: @Sergio’s response is also interesting for more complex situations where the keyframe may be insufficient, in addition to containing a very interesting compatibilization layer.

Note 2: having said that, here is an article (en) which shows that keyframes also has its problems, and one of them is synchronization. It is worth taking a read.

  • 2

    They built this half-crooked dummy. It leans more to the left... :p

  • 1

    @bfavaretto know that the observation has a playful tone (based on true facts :P ), but you can use different angles on each side (for example, -5 and 15 instead of -10 and 10). Obviously in a case like this the right thing to do is to unravel the dummy, but I think that the crooked one contributes to the dramatization of the infinite instability :)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.