Edit in JSFiddle

// prepare the animation canvas and the draw canvas
var animcanvas = document.createElement( 'canvas' ),
    animctx = animcanvas.getContext( '2d' ),
    drawcanvas = document.createElement( 'canvas' ),
    drawctx = drawcanvas.getContext( '2d' );

// dimensions and container element     
var container = document.querySelector('section'),
    height = width = 300,
    halfwidth = width / 2,
    halfheight = height / 2,
    offset = i = x = 0,
    radius = height / 2 - 10;

function init(){
  
  // check if the browser supports CSS animation
  var domPrefixes = 'Webkit Moz O ms Khtml'.split(' ');   
  var pfx = false;
  for(var i = 0; i < domPrefixes.length ;i++ ) {
    if( animcanvas.style[ domPrefixes[i] + 'AnimationName' ] !== undefined ) {
      pfx = domPrefixes[i];
      break;
    }
  }
  
  animcanvas.width = drawcanvas.width = width;
  animcanvas.height = drawcanvas.height = height;

  drawctx.save();
  drawctx.translate( halfwidth, halfheight );

  while( radius > 10 ) {
    drawctx.fillStyle = i % 2 === 0 ? '#000' : '#fff';
    radius -= 6;
    x = Math.sin( i / 2 ) * 10;
    drawctx.beginPath();
    drawctx.arc( x, 0, radius, 0, Math.PI * 2 ,true ); 
    drawctx.closePath();
    drawctx.fill(); 
    i++;
  }

  drawctx.restore();

  // if the browser supports CSS3 animation, create a new animation
  if( pfx !== false ) {
    drawcanvas.style[ pfx + 'AnimationDuration' ] = '1s';
    drawcanvas.style[ pfx + 'AnimationTimingFunction'] = 'linear';
    drawcanvas.style[ pfx + 'AnimationIterationCount'] = 'infinite';
    drawcanvas.style[ pfx + 'AnimationName'] = 'rotate';

    var csspfx = pfx.toLowerCase(),
        keyframes = '@-' + csspfx + '-keyframes rotate { '+
                    'from { -' + csspfx + '-transform:rotate( 0deg ); }'+
                    'to { -' + csspfx + '-transform:rotate( 360deg ); }'+
                    '}';
    if( document.styleSheets && document.styleSheets.length ) {
      document.styleSheets[0].insertRule( keyframes, 0 );
    } else {
      var s = document.createElement( 'style' );
      s.innerHTML = keyframes;
      document.getElementsByTagName( 'head' )[ 0 ].appendChild( s );
    }
    // ^ this makes me feel dirty, is there a cleaner way without 
    //   generating a style element?
    container.appendChild( drawcanvas );
    var msg = document.createElement('span');
    msg.innerHTML += '<span>Using CSS animation</span>';
    container.appendChild(msg);

  // if the browser has no CSS animation, do a canvas animation
  } else {
    container.appendChild( animcanvas );
    var msg = document.createElement( 'span' );
    msg.innerHTML += '<span>Using an animation loop';
    if(requestAnimationFrame.toString().indexOf( 'mation' ) !== -1 ) {
      msg.innerHTML += ' with requestAnimationFrame';
    } else {
      msg.innerHTML += ' without requestAnimationFrame';
    }
    msg.innerHTML += '</span>';
    container.appendChild( msg );
    loop();
  }
}

// canvas animation loop 
function loop(){
  animctx.clearRect( 0, 0, width, height );
  animctx.save();
  animctx.translate( halfwidth, halfheight );
  offset += 0.06;
  animctx.rotate( offset );
  animctx.fill();
  animctx.drawImage( drawcanvas, -halfwidth, -halfheight );
  animctx.restore();
  requestAnimationFrame( loop, 60 );
}

/**
 * Provides requestAnimationFrame in a cross browser way.
 * http://paulirish.com/2011/requestanimationframe-for-smart-animating/
 */
if ( !window.requestAnimationFrame ) {
  window.requestAnimationFrame = ( function() {
    return window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function(  callback, fps ) {
      window.setTimeout( callback, 1000 / fps );
    };
  } )();
}
init();
<section></section>