Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS Animation: Number increment effect

I'm wanting to get that animation effect when numbers change quickly, example: http://jsbin.com/kevalutupe/1/

I'm wanting to do this CSS alone (I know how to code it in JS), I don't want to use JS as I feel hammering the DOM isn't the best solution. Is this at all possible with CSS?

I'm not fussed about the numbers actually incrementing correctly, I'm just after the effect.

like image 455
ditto Avatar asked Jan 15 '15 04:01

ditto


People also ask

How do you make a counter in HTML CSS?

Steps to create HTML counter Step 1: Create the simple structure using HTML <div> tags. Step 2: Add CSS to make the counter more attractive. Step 3: To add the small icons (like suitcase, coffee-cup, Smylie, user icon, book and more) with the counter, use the bootstrap cdn link and code.


1 Answers

The number spinning effect is most definitely possible using CSS3 animations and what's better you can also set the end-point using a small bit of JS and actually get the whole functionality.

Method Explanation:

  1. A div is created such that it will always display only one number by setting its height and width as 1em. Overflow of the div is set to hidden so as to make only one line visible.
  2. Within this div a span containing all the numbers from 1 to 0 is created and is positioned relative to the parent.
  3. Initial position of the span is at 0px or 0em but during the animation the top position is changed so that the span gives the impression of being moved upwards. Because the div can display only one number at a time, it gives the spinning effect (or the effect of the other numbers disappearing).
  4. Final position is achieved by setting a fixed top position to each of the span elements. 0em means the 1st line is visible (number 1), -2em means the third line becomes visible (number 3) and so on.
  5. Increasing or decreasing the animation duration will make the spin effect happen quickly or slowly. The animation iteration count is set to 5 to produce an illusion that the spinner is spinning multiple times.

Note: Using this method, the spin will look like going the whole circle every-time and not like the JSBin sample in question where a 3 to 4 for the first digit would be just a single 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;
  }
}

/* Setting the required value to top will make the spinner end at that number */

#digit1 {
  top: -4em;
  /* -4em means 5 will be the number */
}
#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 below is a sample with JavaScript where the animation effect is achieved through CSS but the triggering of the animation and the setting of the endpoint is achieved using JavaScript.

The JS code is pretty much self explanatory. All we are doing is the following:

  1. Create a listener for the click event of the button and within it we add the animate class to all the span elements which are part of this animation effect. This is because we want the animation to happen only when the button is clicked.
  2. When the animation ends (or the spin is complete), we set the top property of each span to some random number. This would mean that each span will have a different number displayed.
  3. On the end of the animation we are also calling another function to remove the animate class so that when we click the button again the animation can start all over again.

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;
  }
}

/* Set the value according to the on-load position of the spinner */

#digit1 {
  top: -4em;
  /* -4em means 5 will be the number */
}
#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: (with only a number increment effect instead of a spinning effect)

This is created using largely the same code as the previous one but unlike the previous one where the animation makes the movement from one number to another a gradual one (and thereby producing a spin effect), here the animation makes the movement more like a sudden jump from one number to another and thereby produces just an increment effect.

The jump is achieved by maintaining the top position the same till its just about time to move to the next (that is, the top is set to be 0em till 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; }
}

/* Set the value according to the on-load position of the spinner */

#digit1 {
  top: -4em;
  /* -4em means 5 will be the number */
}
#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>
like image 188
Harry Avatar answered Oct 10 '22 23:10

Harry