The effect of spinning a number is most definitely possible using CSS3 animations, and best of all, you can also set the endpoint using a small bit of JS and actually get all the functionality.
Method Explanation:
- A
div is created in such a way that it will always display only one number, setting its height and width to 1em. The div overflow is set to hidden to display only one line. - Inside this
div a span , containing all numbers from 1 to 0, is created and positioned relative to the parent. - The initial position of the
span is 0px or 0em, but during animation top position changes so that the span gives the impression of moving up. Since a div can only display one number at a time, it gives a rotational effect (or the effect of the disappearance of other numbers). - The final position is achieved by setting a fixed top position for each of the
span elements. 0em means that the 1st line is visible (number 1), -2em means that the third line becomes visible (number 3), etc. - Increasing or decreasing the duration of the animation will cause the spin effect to happen quickly or slowly. The animation iteration counter is set to 5 to create the illusion that the counter rotates several times.
Note: Using this method, the spin will look like every time in a circle, and not like the JSBin in question, where from 3 to 4 for the first digit there will be only one step, and not a full circle.
div { width: 1em; height: 1em; overflow: hidden; line-height: 1em; display: inline-block; } span { position: relative; } .animate { -webkit-animation: spinit 0.2s 5; -moz-animation: spinit 0.2s 5; animation: spinit 0.2s 5; } @-webkit-keyframes spinit { 0% { top: 0em; } 50% { top: -5em; } 100% { top: -9em; } } @-moz-keyframes spinit { 0% { top: 0em; } 50% { top: -5em; } 100% { top: -9em; } } @keyframes spinit { 0% { top: 0em; } 50% { top: -5em; } 100% { top: -9em; } } #digit1 { top: -4em; } #digit2 { top: -2em; } #digit3 { top: 0em; }
<div> <span class="animate" id='digit1'>1 2 3 4 5 6 7 8 9 0</span> </div> <div> <span class="animate" id='digit2'>1 2 3 4 5 6 7 8 9 0</span> </div> <div> <span class="animate" id='digit3'>1 2 3 4 5 6 7 8 9 0</span> </div>
The following is an example with JavaScript, where the animation effect is achieved using CSS, but the animation is triggered and the endpoint is set using JavaScript.
JS code pretty much explains itself. All we do is the following:
- Create a listener for the button click event and inside it we will add the
animate class to all span elements that are part of this animation effect. This is because we want the animation to happen only at the click of a button. - When the animation ends (or the end of the rotation), we set the
top property of each span to a random number. This would mean that each interval would be displayed with a different number. - At the end of the animation, we also call another function to remove the
animate class animate that when you click the button again, the animation can start over and over.
window.onload = function() { var spinner = document.getElementById('spinner'); spinner.onclick = spinit; var el = document.querySelectorAll("span[id*=digit]"); for (i = 0; i < el.length; i++) { el[i].addEventListener("animationend", randomize, false); el[i].addEventListener("webkitAnimationEnd", randomize, false); el[i].addEventListener("oanimationend", randomize, false); el[i].addEventListener("MSAnimationEnd", randomize, false); } } function randomize() { var rand = Math.floor(Math.random() * 9); this.style.top = -1 * rand + "em"; this.classList.toggle('animate'); } function spinit() { var el = document.querySelectorAll("span[id*=digit]"); for (i = 0; i < el.length; i++) { el[i].classList.toggle('animate'); } }
div { width: 1em; height: 1em; overflow: hidden; line-height: 1em; display: inline-block; } span { position: relative; } .animate { -webkit-animation: spinit 0.2s 5; -moz-animation: spinit 0.2s 5; animation: spinit 0.2s 5; } @-webkit-keyframes spinit { 0% { top: 0em; } 50% { top: -5em; } 100% { top: -9em; } } @-moz-keyframes spinit { 0% { top: 0em; } 50% { top: -5em; } 100% { top: -9em; } } @keyframes spinit { 0% { top: 0em; } 50% { top: -5em; } 100% { top: -9em; } } #digit1 { top: -4em; } #digit2 { top: -2em; } #digit3 { top: 0em; }
<div> <span id='digit1'>1 2 3 4 5 6 7 8 9 0</span> </div> <div> <span id='digit2'>1 2 3 4 5 6 7 8 9 0</span> </div> <div> <span id='digit3'>1 2 3 4 5 6 7 8 9 0</span> </div> <button id='spinner'>Spin It</button>
Version 2: (only with the effect of increasing the number instead of the spinning effect)
This is created using basically the same code as the previous one, but unlike the previous one, where animation makes the movement from one number to another gradual (and thereby creates a rotation effect), here the animation makes the movement more like a sudden jump from one numbers to another and thus gives an increment effect.
The jump is achieved by keeping the top position the same until its time roughly moves to the next (i.e., the top value is 0em to 9.9% of the animation, but at 10% it suddenly changes to -1em ).
window.onload = function() { var spinner = document.getElementById('spinner'); spinner.onclick = spinit; var el = document.querySelectorAll("span[id*=digit]"); for (i = 0; i < el.length; i++) { el[i].addEventListener("animationend", randomize, false); el[i].addEventListener("webkitAnimationEnd", randomize, false); el[i].addEventListener("oanimationend", randomize, false); el[i].addEventListener("MSAnimationEnd", randomize, false); } } function randomize() { var rand = Math.floor(Math.random() * 9); this.style.top = -1 * rand + "em"; this.classList.toggle('animate'); } function spinit() { var el = document.querySelectorAll("span[id*=digit]"); for (i = 0; i < el.length; i++) { el[i].classList.toggle('animate'); } }
div { width: 1em; height: 1em; overflow: hidden; line-height: 1em; display: inline-block; } span { position: relative; } .animate { -webkit-animation: spinit 0.2s 5; -moz-animation: spinit 0.2s 5; animation: spinit 0.2s 5; } @-webkit-keyframes spinit { 0% { top: 0em; } 9.9% { top: 0em; } 10%{ top: -1em; } 19.9%{ top: -1em; } 20%{ top: -2em; } 29.9%{ top: -2em; } 30%{ top: -3em; } 39.9%{ top: -3em; } 40%{ top: -4em; } 49.9%{ top: -4em; } 50% { top: -5em; } 59.9%{ top: -5em; } 60%{ top: -6em; } 69.9%{ top: -6em; } 70%{ top: -7em; } 79.9%{ top: -7em; } 80%{ top: -8em; } 89.9%{ top: -8em; } 90%{ top: -9em; } 99.9%{ top: -9em; } 100% { top: -9em; } } @-moz-keyframes spinit { 0% { top: 0em; } 9.9% { top: 0em; } 10%{ top: -1em; } 19.9%{ top: -1em; } 20%{ top: -2em; } 29.9%{ top: -2em; } 30%{ top: -3em; } 39.9%{ top: -3em; } 40%{ top: -4em; } 49.9%{ top: -4em; } 50% { top: -5em; } 59.9%{ top: -5em; } 60%{ top: -6em; } 69.9%{ top: -6em; } 70%{ top: -7em; } 79.9%{ top: -7em; } 80%{ top: -8em; } 89.9%{ top: -8em; } 90%{ top: -9em; } 99.9%{ top: -9em; } 100% { top: -9em; } } @keyframes spinit { 0% { top: 0em; } 9.9% { top: 0em; } 10%{ top: -1em; } 19.9%{ top: -1em; } 20%{ top: -2em; } 29.9%{ top: -2em; } 30%{ top: -3em; } 39.9%{ top: -3em; } 40%{ top: -4em; } 49.9%{ top: -4em; } 50% { top: -5em; } 59.9%{ top: -5em; } 60%{ top: -6em; } 69.9%{ top: -6em; } 70%{ top: -7em; } 79.9%{ top: -7em; } 80%{ top: -8em; } 89.9%{ top: -8em; } 90%{ top: -9em; } 99.9%{ top: -9em; } 100% { top: -9em; } } #digit1 { top: -4em; } #digit2 { top: -2em; } #digit3 { top: 0em; }
<div> <span id='digit1'>1 2 3 4 5 6 7 8 9 0</span> </div> <div> <span id='digit2'>1 2 3 4 5 6 7 8 9 0</span> </div> <div> <span id='digit3'>1 2 3 4 5 6 7 8 9 0</span> </div> <button id='spinner'>Spin It</button>
Harry
source share