jQuery: how do I animate a div rotation?

Solution 1:

Make use of WebkitTransform / -moz-transform: rotate(Xdeg). This will not work in IE, but Matt's zachstronaut solution doesn't work in IE either.

If you want to support IE too, you'll have to look into using a canvas like I believe Raphael does.

Here is a simple jQuery snippet that rotates the elements in a jQuery object. Rotation can be started and stopped:

$(function() {
    var $elie = $("img"), degree = 0, timer;
    rotate();
    function rotate() {
        
        $elie.css({ WebkitTransform: 'rotate(' + degree + 'deg)'});  
        $elie.css({ '-moz-transform': 'rotate(' + degree + 'deg)'});                      
        timer = setTimeout(function() {
            ++degree; rotate();
        },5);
    }
    
    $("input").toggle(function() {
        clearTimeout(timer);
    }, function() {
        rotate();
    });
}); 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<input type="button" value=" Toggle Spin " />
<br/><br/><br/><br/>
<img src="http://i.imgur.com/ABktns.jpg" />

Solution 2:

If you're designing for an iOS device or just webkit, you can do it with no JS whatsoever:

CSS:

@-webkit-keyframes spin {  
from {  
    -webkit-transform: rotate(0deg);  
}  
to {  
    -webkit-transform: rotate(360deg);  
    } 
}

.wheel {
    width:40px;
    height:40px;
    background:url(wheel.png);
    -webkit-animation-name: spin; 
    -webkit-animation-iteration-count: infinite; 
    -webkit-animation-timing-function: linear;
    -webkit-animation-duration: 3s; 
}

This would trigger the animation on load. If you wanted to trigger it on hover, it might look like this:

.wheel {
    width:40px;
    height:40px;
    background:url(wheel.png);
}

.wheel:hover {
    -webkit-animation-name: spin; 
    -webkit-animation-iteration-count: infinite; 
    -webkit-animation-timing-function: ease-in-out;
    -webkit-animation-duration: 3s; 
}

Solution 3:

I've been using

$.fn.rotate = function(degrees, step, current) {
    var self = $(this);
    current = current || 0;
    step = step || 5;
    current += step;
    self.css({
        '-webkit-transform' : 'rotate(' + current + 'deg)',
        '-moz-transform' : 'rotate(' + current + 'deg)',
        '-ms-transform' : 'rotate(' + current + 'deg)',
        'transform' : 'rotate(' + current + 'deg)'
    });
    if (current != degrees) {
        setTimeout(function() {
            self.rotate(degrees, step, current);
        }, 5);
    }
};

$(".r90").click(function() { $("span").rotate(90) });
$(".r0").click(function() { $("span").rotate(0, -5, 90) });
span { display: inline-block }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<span>potato</span>

<button class="r90">90 degrees</button>
<button class="r0">0 degrees</button>

Solution 4:

If you want just a jQuery option, this will work:

$(el).stop().animate(
  {rotation: 360},
  {
    duration: 500,
    step: function(now, fx) {
      $(this).css({"transform": "rotate("+now+"deg)"});
    }
  }
);

This works with jQuery 1.8, which takes care of CSS prefixing automatically. jQuery doesn't animate rotation so I'm putting the transform:rotate() in the custom step function. It might only work starting from 0.

Demo: http://jsfiddle.net/forresto/ShUgD/

IE9 and Mobile Safari 4 support CSS transforms but not CSS transitions, so I came up with this simple shim, using Modernizr feature testing:

if (Modernizr.csstransitions) {
  $(el).css({
    "transition": "all 500ms ease-in-out"
  });
}

$(el).click(function(){
  var rotateTo = 360;
  if (Modernizr.csstransitions) {
    $(el).css({"transform": "rotate("+rotateTo+"deg)"});
  } else {
    $(el).stop().animate(
      {rotation: rotateTo},
      {
        duration: 500,
        step: function(now, fx) {
          $(this).css({"transform": "rotate("+now+"deg)"});
        }
      }
    );
  }
});

The above will use CSS transitions when available.