countdown timer with css animation
by Stalk
HTML
<div class="timer" id="a">
<div class="display">
<div class="symbol"><div class="cur"></div><div class="old"></div></div>
<div class="symbol"><div class="cur"></div><div class="old"></div></div>
<div class="delimeter">:</div>
<div class="symbol"><div class="cur"></div><div class="old"></div></div>
<div class="symbol"><div class="cur"></div><div class="old"></div></div>
<div class="delimeter">:</div>
<div class="symbol"><div class="cur"></div><div class="old"></div></div>
<div class="symbol"><div class="cur"></div><div class="old"></div></div>
</div>
</div>
<div class="timer other">
<div class="display">
<div class="symbol"><div class="cur"></div><div class="old"></div></div>
<div class="symbol"><div class="cur"></div><div class="old"></div></div>
<div class="delimeter">:</div>
<div class="symbol"><div class="cur"></div><div class="old"></div></div>
<div class="symbol"><div class="cur"></div><div class="old"></div></div>
<div class="delimeter">:</div>
<div class="symbol"><div class="cur"></div><div class="old"></div></div>
<div class="symbol"><div class="cur"></div><div class="old"></div></div>
</div>
</div>
CSS
html, body{margin: 0px;background-color: #20262e;}
.timer {
width: 210px;
margin: 10px auto 0px auto;
font-family: Comic Sans MS;
font-size: 20px;
color: #fff;
cursor: default;
text-align: center;
line-height: 40px;
border-radius: 10px;
cursor: default;
}
.display {
width: 180px;
height: 50px;
height: 90px;
margin: 0px auto 0px auto;
color: #ffffff;
padding: 10px 0px 10px 0px;
}
.symbol {
width: 27px;
height: 50px;
float: left;
overflow: hidden;
}
.symbol div {
}
.cur,.old{
width: 92%;
height: 40px;
float: left;
background-color: #3F51B5;
border-radius: 3px;
margin: 5px 1px;
transform: translateY(-50px);
box-shadow: inset 1px 1px 3px 0px rgba(255, 255, 255, 0.5);
}
.symbol.anim div {
transform: translateY(0px);
transition: transform .7s ease-in-out;
}
.delimeter {
width: 9px;
float: left;
line-height: 47px;
margin-left: 0px;
text-indent: 0px;
}
.other .symbol div {
background-color: tomato;
}
JavaScript
function countdown(dateStr, displayElem, onTimerEnd = null) {
let targetDate = new Date(dateStr).getTime();
let displaySymbols = [...displayElem.querySelectorAll('.symbol .cur')]
let prevValue = ' '
let timer = setInterval(function() {
let now = new Date().getTime();
let remainingTime = targetDate - now;
if (remainingTime <= 0) {
clearInterval(timer) // stop timer
if (onTimerEnd) {
onTimerEnd() // run callback
}
}
let formattedTimestr = format(remainingTime);
updateDisplay(formattedTimestr);
}, 1000);
function format(time) {
return [time % 86400000 / 3600000, // hours
time % 3600000 / 60000, // minutes
time % 60000 / 1000] // seconds
.map(x => Math.floor(x).toString().padStart(2, '0'))
.join('')
}
function updateDisplay(timeString) {
displaySymbols.forEach((curSymbol, i) => {
let newValue = timeString[i]
let currentValue = prevValue[i]
if (currentValue !== newValue) { // animated change
let parent = curSymbol.parentNode
parent.classList.remove('anim')
curSymbol.textContent = newValue
curSymbol.nextElementSibling.textContent = currentValue
var foo = parent.offsetWidth; // reflow hack
parent.classList.add('anim')
}
})
prevValue = timeString
}
}
countdown('2033-02-10 00:00:00', document.getElementById('a'))
countdown('2033-02-10 04:20:00', document.querySelector('.other'))