JSFiddle - React, Tailwind, and code Playground
by Mladen Mihajlovic
HTML
<div id="odometer">
<div class="digit">0</div>
<div class="digit">0</div>
<div class="digit">0</div>
</div>
CSS
#odometer {
display: flex;
justify-content: center;
align-items: center;
width: 150px;
height: 50px;
background-color: #eee;
font-size: 24px;
font-weight: bold;
}
.digit {
position: relative;
width: 30px;
height: 50px;
margin-right: 5px;
overflow: hidden;
}
.digit:before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #fff;
transform: translateY(0);
transition: transform 0.5s ease-out;
}
.digit:after {
content: "";
position: absolute;
top: -100%;
left: 0;
width: 100%;
height: 100%;
background-color: #fff;
}
@keyframes scroll {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-300%);
}
}
.digit.animate:before {
animation: scroll 1.5s ease-out forwards;
}
JavaScript
function scrollNumber(number) {
const digits = document.querySelectorAll("#odometer .digit");
const numbers = Array.from(String(number), Number);
digits.forEach((digit, i) => {
if (numbers[i] !== undefined) {
digit.classList.add("animate");
const target = digit.querySelector(":before");
target.style.transform = `translateY(-${numbers[i] * 50}%)`;
} else {
digit.classList.remove("animate");
}
});
// Wait for animation to finish before resetting
setTimeout(() => {
digits.forEach((digit) => {
digit.classList.remove("animate");
const target = digit.querySelector(":before");
target.style.transform = `translateY(0)`;
});
}, 1500);
}
scrollNumber(123);