<div class='numCounter' data-value='1234567'></div>
View Compiled
$digitHeight : 90px;
$speed : .5s;
$baseColor : #55b9f3;
$textColor : white;
.numCounter{
display: inline-block;
height: $digitHeight;
line-height: $digitHeight;
text-shadow: 0 0 2px #FFF;
font-weight: bold;
white-space: normal;
font-size: $digitHeight/1.5;
> div{
display: inline-block;
vertical-align: top;
height: 100%;
> b{
display: inline-block;
width: $digitHeight/1.4;
height: 100%;
margin: 0 .1em;
border-radius: 8px;
text-align: center;
text-shadow: 2px 1px 3px rgba(black, .2);
box-shadow: 2px 2px 3px rgba(black, .1) inset,
-2px -2px 2px rgba(white, .12) inset;
overflow: hidden;
&::before{
content:' 0 1 2 3 4 5 6 7 8 9 ';
display:block;
word-break:break-all;
word-break:break-word;
transition: $speed cubic-bezier(.75, .15,.6, 1.15),
text-shadow 150ms;
}
&.blur{
opacity: .8;
text-shadow: 2px 1px 3px rgba(black, .2),
0 .1em 2px rgba($textColor, .6),
0 .3em 3px rgba($textColor, .3),
0 -.1em 2px rgba($textColor, .6),
0 -.3em 3px rgba($textColor, .3);
}
@for $i from 1 through 9{
&[data-value="#{$i}"]::before{ margin-top:-$digitHeight * $i; }
}
}
// format number (US-format)
&:nth-last-child(3n):not(:first-child){
&::before{
content:",";
display:inline;
font-size: 1.1em;
opacity: .6;
color: white;
}
}
}
}
////////////////////////////////////////
// DEMO ONLY
@import url('https://fonts.googleapis.com/css?family=Fjalla+One&display=swap');
html,body{ height:100%; }
body{
display: flex;
align-items: center;
justify-content: center;
background: $baseColor;
font-family: 'Fjalla One', Arial;
perspective:1000px;
}
.numCounter{
overflow:hidden;
padding: .4em;
text-align:center;
border-top: 1px solid rgba(white, .1);
border-left: .5px solid rgba(white, .01);
// background:linear-gradient(to bottom, #555 1%, #333 4%, #1a1a1a 98%, #000 100%);
border-radius: 16px;
// box-shadow:0 5px 12px #111, 0 0 8px 0 rgba(255,255,255,.1) inset;
background: linear-gradient(330deg, scale-color($baseColor, $lightness: 16%, $saturation: 10% ),
scale-color($baseColor, $lightness: -14%, $saturation:-20% ));
box-shadow: -20px -20px 60px scale-color($baseColor, $lightness: -25%, $saturation:-30% ),
20px 20px 60px scale-color($baseColor, $lightness: 25%, $saturation: 30% );
b{
background: scale-color($baseColor, $lightness: -10%, $saturation: -10% );
background: linear-gradient(-30deg, scale-color($baseColor, $lightness: 8%, $saturation: 5% ),
scale-color($baseColor, $lightness: -20%, $saturation:-22% ));
color: $textColor;
}
}
View Compiled
function Counter(selector, settings){
this.settings = Object.assign({
digits: 5,
delay: 250, // ms
direction: '' // ltr is default
}, settings || {})
this.DOM = {}
this.build(selector)
this.DOM.scope.addEventListener('transitionend', e => {
if (e.pseudoElement === "::before" && e.propertyName == 'margin-top'){
e.target.classList.remove('blur')
}
})
this.count()
}
Counter.prototype = {
// generate digits markup
build( selector ){
var scopeElm = typeof selector == 'string'
? document.querySelector(selector)
: selector
? selector
: this.DOM.scope
scopeElm.innerHTML = Array(this.settings.digits + 1)
.join('<div><b data-value="0"></b></div>');
this.DOM = {
scope : scopeElm,
digits : scopeElm.querySelectorAll('b')
}
},
count( newVal ){
var countTo, className,
settings = this.settings,
digitsElms = this.DOM.digits;
// update instance's value
this.value = newVal || this.DOM.scope.dataset.value|0
if( !this.value ) return;
// convert value into an array of numbers
countTo = (this.value+'').split('')
if( settings.direction == 'rtl' ){
countTo = countTo.reverse()
digitsElms = [].slice.call(digitsElms).reverse()
}
// loop on each number element and change it
digitsElms.forEach(function(item, i){
if( +item.dataset.value != countTo[i] && countTo[i] >= 0 )
setTimeout(function(j){
var diff = Math.abs(countTo[j] - +item.dataset.value);
item.dataset.value = countTo[j]
if( diff > 3 )
item.className = 'blur';
}, i * settings.delay, i)
})
}
}
/////////////// create new counter for this demo ///////////////////////
var counter = new Counter('.numCounter', {
direction : 'rtl',
delay : 200,
digits : 7
})
// change counter value every N seconds
var counterInterval = setInterval(randomCount, 3000)
function randomCount(){
counter.count( +(""+Math.random()).substring(2, 2+counter.settings.digits) )
}
function getRandomNum(min,max){
return Math.floor(Math.random()*(max-min+1) + min)
}
/////////////// Controls ///////////////////////
var settings = {
visible: 0,
CSSVarTarget: document.querySelector('.numCounter'),
knobs: [
{
label: 'Number of Digits',
type: 'range',
value: 7,
min: 1,
max: 12,
onChange: e => {
clearInterval(counterInterval)
counter.settings.digits = +e.target.value;
counter.build()
counterInterval = setInterval(randomCount, 3000)
randomCount()
}
},
{
label: 'Delay',
type: 'range',
value: 200,
min: 0,
max: 400,
step: 25,
onChange: e => counter.settings.delay = +e.target.value
},
{
cssVar: ['hide'], // alias for the CSS variable
label: 'Animate Right-To-Left',
type: 'checkbox',
checked: true,
value: 'none',
onChange: e => counter.settings.direction = e.target.checked ? "rtl" : ""
}
]
}
var myKnobs = new Knobs(settings)
This Pen doesn't use any external CSS resources.