0
1
2
3
4
5
6
7
8
9
F
0
1
2
3
4
5
6
7
8
9
I
0
1
2
3
4
5
6
7
8
9
N
0
1
2
3
4
5
6
7
8
9
I
0
1
2
3
4
5
6
7
8
9
S
0
1
2
3
4
5
6
7
8
9
H
1

interval increase by +1

8
1
8
1
8
1
,
8
1
8
1
8
1
2

start animation on scroll with GSAP ScrollTrigger

8
1
8
1
8
1
8
1
,
8
1
8
1
8
1
.
8
1
8
1
8
1
3

on scroll with currency symbol

8
1
8
1
.
8
1
8
0
8
0
,
8
1
8
1
8
1
4

interval with custom increase

8
1
8
1
,
8
1
8
1
8
1
5

inline with random increase

812,000+ sites were #MadeInWebflow in 2022 so far.

6

animate on click

8
1
8
1
,
8
1
8
1
8
1
2019
2020
2021

Education section for better understanding

You can apply your odometer to any element you want. It can be an empty div or a div with content. The only important thing is that the classes generated by Odometer are styled in some way, so that your Odometer 1. looks like you want it to and 2. works properly. In our example we have already built every odometer (except the 5th one) as it would be generated by the odometer script.

To understand what happens after initializing the script with a div you want to have as odometer, see the following view:

In Webflow / Before the script was executed
.your-odometer
After the script is executed
.your-odometer
.odometer-inside
.odometer-digit
.odometer-digit-spacer
.odometer-digit-inner
.odometer-ribbon
.odometer-ribbon-inner
.odometer-value
.odometer-digit
.odometer-digit-spacer
.odometer-digit-inner
.odometer-ribbon
.odometer-ribbon-inner
.odometer-value
.odometer-formatting-mark
.odometer-digit
And so on

So depending on the size of the generated number of your odometer, this can get quite complex, but it follows a clear scheme. For this reason it can be very worthwhile, especially because we work visually in Webflow, to build and style the structure once already in Webflow - as we did in our examples (except for the 5th one).

Hubspot provides together with the script also some themes, which can take over the styling of the odometer for you. However, since we tend to avoid that kind of thing and want each component to be as individual as possible, we built our own "themes" (if you like to call them that).

Below is a starter build for you, which already includes all the styles we can define in native Webflow.

8
1
8
2
8
3
,
8
4
8
5

Since Webflow unfortunately still doesn't let you set some important CSS properties natively, which we still need for the Odometer, you can find a CSS snippet below, which you have to add for your Odometer via embed:

.starter-odometer {
  /* Change regular animation speed
  A bit of trial and error is required here, 
  as this value is related to the interval 
  and duration in the script. */
  --time: 2s;
  /* Specify your desired easing here */
  --odometer-easing: ease;
  vertical-align: middle;
}

.starter-odometer .odometer-inside {
  /* Flex spacing between Elements - works only if .odometer-inside 
  is set to flex oder inline-flex */
  gap: 0.5rem;
}

.starter-odometer .odometer-digit {
  display: inline-block;
  vertical-align: middle;
}

.starter-odometer .odometer-digit .odometer-digit-spacer {
  display: block;
  vertical-align: middle;
  visibility: hidden;
}

.starter-odometer .odometer-digit .odometer-value.odometer-last-value {
  position: absolute;
  left: 0%;
  right: 0%;
}

.starter-odometer .odometer-ribbon-inner {
  -webkit-backface-visibility: hidden;
}

.starter-odometer.odometer-animating-up .odometer-ribbon-inner {
  -webkit-transition: -webkit-transform var(--time);
  -moz-transition: -moz-transform var(--time);
  -ms-transition: -ms-transform var(--time);
  -o-transition: -o-transform var(--time);
  transition: transform var(--time);
}

.starter-odometer.odometer-animating-up.odometer-animating .odometer-ribbon-inner {
  -webkit-transform: translateY(-100%);
  -moz-transform: translateY(-100%);
  -ms-transform: translateY(-100%);
  -o-transform: translateY(-100%);
  transform: translateY(-100%);
}

.starter-odometer.odometer-animating-down .odometer-ribbon-inner {
  -webkit-transform: translateY(-100%);
  -moz-transform: translateY(-100%);
  -ms-transform: translateY(-100%);
  -o-transform: translateY(-100%);
  transform: translateY(-100%);
}

.starter-odometer.odometer-animating-down.odometer-animating .odometer-ribbon-inner {
  -webkit-transition: -webkit-transform var(--time);
  -moz-transition: -moz-transform var(--time);
  -ms-transition: -ms-transform var(--time);
  -o-transition: -o-transform var(--time);
  transition: transform var(--time);
  -webkit-transform: translateY(0);
  -moz-transform: translateY(0);
  -ms-transform: translateY(0);
  -o-transform: translateY(0);
  transform: translateY(0);
}

.starter-odometer.odometer-animating-up .odometer-ribbon-inner,
.starter-odometer.odometer-animating-down.odometer-animating .odometer-ribbon-inner {
  -webkit-transition-timing-function: var(--odometer-easing);
  -moz-transition-timing-function: var(--odometer-easing);
  -ms-transition-timing-function: var(--odometer-easing);
  -o-transition-timing-function: var(--odometer-easing);
  transition-timing-function: var(--odometer-easing);
}

.starter-odometer .odometer-digit .odometer-value {
  -webkit-transform: translateZ(0);
}

Animate from 0000 to e.g. 2022

Tip: If you plan to animate from a 0 value to a number of your choice, as in examples 2 and 3, you should consider the following:

  • 1.

    The odometer script renders only a single 0 for e.g. a start value of 0000, the remaining zeros are not rendered until the animation starts. This does not look good and also causes an unnatural looking jumping in the layout.

  • 2.

    As a workaround for this provides our customized startValue in the script (eg "1" + "0000" + "1"), which adds a number at the beginning and end of your desired number. The problem now is that these numbers are also visible in the final odometer of your project. This is where a small CSS snippet comes into play that will help you to hide the first and last digit as well as the formatting mark if necessary.

.your-odometer .odometer-inside .odometer-digit:nth-child(1),
.your-odometer .odometer-inside .odometer-digit:last-child {
    display: none
}

/* Optional hide specific formatting mark */
.your-odometer .odometer-inside .odometer-formatting-mark:nth-child(NUMBER) {
    display: none
}
Clone, create & have fun ↗
And of course, we welcome feedback or a heart.