After learning all the possible ways to create an easy and flexible counter, I ended up using requestAnimationFrame , which is pretty brilliant. It basically does the same thing as CSS3 animation : performs calculations and passes the result to the browser in order to synchronize the redrawing with the redrawing of the screen (usually at 60 frames per second). Although CSS3 transition and animation are suitable for very simple use, since there is only a transitionend event that may not fire under certain circumstances, requestAnimationFrame offers full control, and you can perform many complex calculations perfectly in sync with the screen redrawing.
Would it be worthwhile to surpass this code in a working HTML5 document?
CSS
i.spinner {position:relative;display:inline-block;margin:20px} i.bar {display:block;position:absolute;top:0;left:50%;height:inherit} i.bar i {display:block;width:100%;height:29%;background:#000} i.bar:nth-child(2) {transform:rotate(45deg);-webkit-Transform:rotate(45deg);-moz-Transform:rotate(45deg);-ms-Transform:rotate(45deg)} i.bar:nth-child(3) {transform:rotate(90deg);-webkit-Transform:rotate(90deg);-moz-Transform:rotate(90deg);-ms-Transform:rotate(90deg)} i.bar:nth-child(4) {transform:rotate(135deg);-webkit-Transform:rotate(135deg);-moz-Transform:rotate(135deg);-ms-Transform:rotate(135deg)} i.bar:nth-child(5) {transform:rotate(180deg);-webkit-Transform:rotate(180deg);-moz-Transform:rotate(180deg);-ms-Transform:rotate(180deg)} i.bar:nth-child(6) {transform:rotate(225deg);-webkit-Transform:rotate(225deg);-moz-Transform:rotate(225deg);-ms-Transform:rotate(225deg)} i.bar:nth-child(7) {transform:rotate(270deg);-webkit-Transform:rotate(270deg);-moz-Transform:rotate(270deg);-ms-Transform:rotate(270deg)} i.bar:nth-child(8) {transform:rotate(315deg);-webkit-Transform:rotate(315deg);-moz-Transform:rotate(315deg);-ms-Transform:rotate(315deg)}
Js
function buildspinner(size, invert) { var color = '#000', spinner = document.createElement('i'), bar = document.createElement('i'), hand = document.createElement('i'), opacitymap = [0.8, 0.2, 0.2, 0.2, 0.2, 0.5, 0.6, 0.7], nodemap = []; if (invert) {color = '#fff'}; spinner.className = 'spinner'; spinner.style.cssText = 'width:' + size + 'px;height:' + size + 'px'; bar.className = 'bar'; bar.style.cssText = 'width:' + (size / 9) + 'px;height:' + size + 'px;margin-left:' + (-size / 18) + 'px'; hand.style.cssText = 'border-radius:' + size + 'px;background:' + color; bar.appendChild(hand); for (var j = 0; j < 8; j++) { var clone = bar.cloneNode(true); clone.style.opacity = opacitymap[j]; spinner.appendChild(clone); nodemap.push(clone) } document.body.appendChild(spinner); requestAnimationFrame(function(timestamp) {animatespinner(timestamp, timestamp, 125, opacitymap, nodemap, 0)}) } function animatespinner(starttime, timestamp, duration, opacitymap, nodemap, counter) { var progress = (timestamp - starttime) / duration; counter++; if (counter % 3 == 0) { for (var j = 0; j < 8; j++) { var next = j - 1; if (next < 0) { next = 7 }; nodemap[j].style.opacity = (opacitymap[j] + (opacitymap[next] - opacitymap[j]) * progress) } } if (progress < 1) { requestAnimationFrame(function(timestamp) {animatespinner(starttime, timestamp, 125, opacitymap, nodemap, counter)}) } else { var rotatearray = opacitymap.pop(); opacitymap.unshift(rotatearray); requestAnimationFrame(function(timestamp) {animatespinner(timestamp, timestamp, 125, opacitymap, nodemap, 0)}) } }
The counter variable is used for throttling. You want the animation to be smooth, but you want the CPU to be low. In this example, we change the opacity every 3 frames instead of each frame, greatly reducing the CPU load with a noticeable effect on smoothness. (CPU usage decreased from 12% to 5% on the Quadcore 3GHz processor).
Since CSS3 animation relies on keyframes , you will need to create a separate keyframe for each side of the counter, which will lead to too much computation. The same counter created using CSS3 animations resulted in 30% CPU utilization.
Demo