Animated Countdown

No extra elements needed

Live Demo

Thu Jul 29 2021

An animated countdown where each digit animates by moving from top to bottom, without using extra elements for each digit - only the :before pseudo-element.

I needed to create a simple countdown to a given time but I thought I would spice it up a little bit with some animation. I've always liked where the next digit seems to fall from the top and pushes the current digit down. There are plenty of examples of this online, but a lot of them seem to use extra elements for each digit, or at least one extra.

Which had me thinking, "Why not use the :before pseudo-element as the 'next digit', animate the element moving down, and then replace the element with the next digit?" And that's exactly what I managed to do!

Moving the Digit

The basic idea behind this idea is the following CSS:

span {
  position: relative;

span:before {
  content: attr(data-nextvalue);
  position: absolute;
  top: -80px;
  z-index: -1;

span.moving {
  transition: transform 500ms ease;
  transform: translateY(80px);

Imagine the span element is a digit. We set it's positioning to relative and we set it's :before pseudo-element's content to the next digit (shown later). The :before element's positioning is set to absolute and it's moved above the span element with top.

Now when we want to move the digit downwards, we simply apply the .moving class to it which will translate the element down by 80px over 500ms using a combination of transition and transform.

Setting the Digit's Next Value

To set the digit's next value, we use a data attribute. We can set this in javascript with the following:

digit.dataset.nextvalue = nextValue;

This is then set using the content rule in the CSS above.

Replacing the Digit

Once the transform has finished, we need to set the digit to it's next value. We do this by removing the moving class and setting the digit's innerHTML to the next value after 500ms.

setTimeout(() => {
  digit.innerHTML = nextValue;
}, 500);

Wrapping Up

You can see the full code example on my CodePen: