.clock-wrapper
.bg
.knob
.knob-lines#knob-lines
- (0..14).each do |i|
.knob-line
.btn#ampm
.btn.radio-btn#radio-btn
%span radio
.logo Ika
.minutes
.dizaines
- (0..5).each do |i|
.number{:id => "minutes-dizaines-#{i}"}
.up
.digit #{i}
.down
.digit #{i}
.unites
- (0..9).each do |i|
.number{:id => "minutes-unites-#{i}"}
.up
.digit #{i}
.down
.digit #{i}
.hours
.dizaines
- (0..1).each do |i|
.number{:id => "hours-dizaines-#{i}"}
.up
.digit #{i}
.down
.digit #{i}
.unites
- (0..9).each do |i|
.number{:id => "hours-unites-#{i}"}
.up
.digit #{i}
.down
.digit #{i}
.seconds-wrapper
#seconds.seconds
- (0..59).each do |i|
.second #{i}
View Compiled
$colors-beige: (
100: #eeead1,
200: #eadfb5,
300: #c4baaf
);
$colors-green: (
100: #10ffa6,
200: #6fd1b5,
300: #6ac5a9
);
$colors-purple: (
100: #6e4875,
200: #472c4b
);
$colors-yellow: (
100: #fdb800
);
$colors-red: (
100: #f85302
);
$colors-blue: (
100: #00f1ff
);
body {
background: map-get($colors-green, 200);
font-family: 'ATC Duel';
text-align: center;
}
.minutes,
.hours,
.unites,
.dizaines,
.number,
.logo,
.btn,
.seconds-wrapper,
.seconds,
.second,
.seconds-wrapper:before,
.clock-wrapper:before,
.clock-wrapper:after,
.up,
.down,
.digit,
.knob,
.knob-lines,
.hours:before,
.bg { position: absolute; }
.clock-wrapper {
position: relative;
z-index: 1;
display: inline-block;
margin: 33.5vmin 8.5vmin;
width: 83vmin;
height: 26.5vmin;
&:before {
right: 5vmin;
bottom: -4vmin;
left: 5vmin;
display: block;
height: 4vmin;
background: map-get($colors-beige, 200);
border-top: 1vmin solid map-get($colors-green, 300);
content: '';
transform: perspective(200px) rotateX(10deg);
}
&:after {
bottom: -4vmin;
z-index: -1;
display: block;
width: 100%;
height: 100%;
background: map-get($colors-green, 300);
border-radius: 1vmin;
content: '';
transform: perspective(100vmin) rotateX(60deg) skew(60deg);
transform-origin: bottom right;
}
.bg {
width: 100%;
height: 100%;
background: map-get($colors-beige, 100);
border-radius: 1vmin;
}
}
.seconds-wrapper {
top: 5vmin;
right: 16vmin;
bottom: 5vmin;
width: 8vmin;
overflow: hidden;
background: map-get($colors-purple, 200);
border-radius: 0.5vmin;
&:before {
top: 50%;
left: 0;
z-index: 1;
display: block;
border: 1vmin solid transparent;
border-right-width: 3.66vmin;
border-left: 3.66vmin solid map-get($colors-red, 100);
content: '';
transform: translateY(-50%);
}
}
.seconds {
top: 50%;
margin-top: 1.3vmin;
transform-style: preserve-3d;
backface-visibility: hidden;
animation: secondsTick 60s infinite linear;
animation-play-state: paused;
}
@-webkit-keyframes secondsTick {
0% { transform: rotateX(0deg); }
100% { transform: rotateX(-360deg); }
}
@-moz-keyframes secondsTick {
0% { transform: rotateX(0deg); }
100% { transform: rotateX(-360deg); }
}
@-ms-keyframes secondsTick {
0% { transform: rotateX(0deg); }
100% { transform: rotateX(-360deg); }
}
@keyframes secondsTick {
0% { transform: rotateX(0deg); }
100% { transform: rotateX(-360deg); }
}
.second {
font-size: 1.5vmin;
color: map-get($colors-yellow, 100);
text-align: center;
white-space: nowrap;
line-height: 2.6vmin;
letter-spacing: 0.05em;
backface-visibility: hidden;
&:before {
display: inline-block;
margin: -0.3vmin 1.3vmin 0 1vmin;
width: 2.6vmin;
height: 0.26vmin;
background: currentColor;
content: '';
vertical-align: middle;
}
@for $i from 1 to 61 {
&:nth-child(#{$i}) {
transform: rotateX(#{$i * 6}deg) translateZ(24.737347581vmin);
}
}
}
.btn {
top: 12.5vmin;
right: 5vmin;
padding: 1.3vmin 0 1.1vmin;
width: 6.5vmin;
background: currentColor;
box-shadow:
inset 0 0 3vmin rgba(black, 0.2),
0 0 6vmin rgba(lighten(map-get($colors-green, 100), 20%), 0.75);
color: map-get($colors-green, 100);
line-height: 1;
font-family: 'ATC Timberline';
font-size: 1vmin;
text-transform: uppercase;
text-align: center;
span {
color: white;
transition: color 0.3s;
}
}
.radio-btn {
top: auto;
bottom: 5vmin;
cursor: pointer;
box-shadow:
inset 0 0 3vmin rgba(black, 0.2),
0 0 6vmin rgba(lighten(map-get($colors-blue, 100), 20%), 0.75);
color: map-get($colors-blue, 100);
transition: box-shadow 0.3s;
span {
color: rgba(white, 0.7);
}
&:hover,
&.is-active {
box-shadow:
inset 0 0 3vmin rgba(black, 0.3),
0 0 6vmin rgba(lighten(map-get($colors-blue, 100), 20%), 1);
span { color: white; }
}
}
.logo {
top: 5vmin;
right: 5vmin;
font-family: 'ATC Timberline';
color: map-get($colors-purple, 200);
text-transform: uppercase;
font-size: 2.6vmin;
line-height: 1;
}
.minutes,
.hours {
top: 5vmin;
bottom: 5vmin;
width: 25vmin;
}
.minutes { right: 26vmin; }
.hours { left: 5vmin; }
.unites, .dizaines { width: calc(50% - 1vmin); }
.unites { right: 0; }
.dizaines { left: 0; }
.hours {
&:before {
top: 50%;
right: -1.3vmin;
display: block;
margin-top: -2vmin;
width: 0.8vmin;
height: 4vmin;
background: map-get($colors-purple, 100);
content: '';
}
}
.number {
width: 100%;
height: 16.5vmin;
color: map-get($colors-yellow, 100);
font-size: 12vmin;
line-height: 16vmin;
&.is-active {
animation: zIndexUp 0.5s forwards;
}
&.outgoing {
animation: zIndexDown 0.5s forwards;
}
}
@-webkit-keyframes zIndexUp {
0% { z-index: 1; }
100% { z-index: 2; }
}
@-moz-keyframes zIndexUp {
0% { z-index: 1; }
100% { z-index: 2; }
}
@-ms-keyframes zIndexUp {
0% { z-index: 1; }
100% { z-index: 2; }
}
@keyframes zIndexUp {
0% { z-index: 1; }
100% { z-index: 2; }
}
@-webkit-keyframes zIndexDown {
0% { z-index: 2; }
100% { z-index: 1; }
}
@-moz-keyframes zIndexDown {
0% { z-index: 2; }
100% { z-index: 1; }
}
@-ms-keyframes zIndexDown {
0% { z-index: 2; }
100% { z-index: 1; }
}
@keyframes zIndexDown {
0% { z-index: 2; }
100% { z-index: 1; }
}
.up,
.down {
width: 100%;
height: calc(50% - 1px);
overflow: hidden;
background: map-get($colors-purple, 200);
border-radius: 0.7vmin;
transform-style: preserve-3d;
backface-visibility: hidden;
transition: none;
&:before {
position: absolute;
z-index: 1;
display: block;
width: 100%;
height: 100%;
content: '';
transition: opactiy 0.25s;
}
}
.up {
top: 0;
transform-origin: bottom center;
&:before {
bottom: 0;
background: linear-gradient(to top, rgba(black, 0.5), transparent);
}
.digit { line-height: 15vmin; }
}
.down {
bottom: 0;
transform: perspective(100vmin) rotateX(180deg);
transform-origin: top center;
&:before {
top: 0;
background: linear-gradient(to bottom, rgba(black, 0.5), transparent);
}
.digit {
bottom: 0;
line-height: 18vmin;
}
}
.digit { width: 100%; }
.is-active {
.up:before,
.down:before { opacity: 0; }
.down {
transform: perspective(100vmin) rotateX(0deg);
transition: transform 0.5s;
}
}
.outgoing {
.up {
transform: perspective(100vmin) rotateX(-180deg);
transition: transform 0.5s;
}
.down {
transform: perspective(100vmin) rotateX(0deg);
transition: transform 0.5s;
}
}
.knob {
top: 50%;
right: -4vmin;
width: 3vmin;
height: 15vmin;
background: map-get($colors-beige, 100);
border-radius: 0 1vmin 1vmin 0;
transform: translateY(-50%);
}
.knob-lines {
top: 50%;
right: -3vmin;
transform-style: preserve-3d;
backface-visibility: hidden;
transform: translateY(-50%);
}
.knob-line {
margin: 0.75vmin 0;
width: 2.6vmin;
height: 0.25vmin;
background: map-get($colors-purple, 200);
}
View Compiled
function startTime() {
var today=new Date();
var h=today.getHours();
var m=today.getMinutes();
var ampm = h >= 12 ? 'pm' : 'am';
h = h % 12;
h = h ? h : 12; // the hour '0' should be '12'
h = String(checkTime(h)).split('');
m = String(checkTime(m)).split('');
// let's clear the old outgoing
var oldOutgoing = document.querySelectorAll('.outgoing');
var i;
for (i = 0; i < oldOutgoing.length; i++) {
oldOutgoing[i].className = 'number';
}
// let's get minutes going
var minutesDizainesOutgoingId = m[0] - 1 === -1 ? 5 : m[0] - 1;
var minutesDizainesOutgoing = document.getElementById('minutes-dizaines-' + minutesDizainesOutgoingId);
var minutesDizaines = document.getElementById('minutes-dizaines-' + m[0]);
var minutesUnitesOutgoingId = m[1] - 1 === -1 ? 9 : m[1] - 1;
var minutesUnitesOutgoing = document.getElementById('minutes-unites-' + minutesUnitesOutgoingId);
var minutesUnites = document.getElementById('minutes-unites-' + m[1]);
minutesDizaines.className = 'number is-active';
minutesDizainesOutgoing.className = 'number outgoing';
minutesUnites.className = 'number is-active';
minutesUnitesOutgoing.className = 'number outgoing';
// clear outgoing
// let's get hours going
var hoursDizainesOutgoingId = h[0] - 1 === -1 ? 1 : h[0] - 1;
var hoursDizainesOutgoing = document.getElementById('hours-dizaines-' + hoursDizainesOutgoingId);
var hoursDizaines = document.getElementById('hours-dizaines-' + h[0]);
var hoursUnitesOutgoingId = h[1] - 1 === -1 ? 9 : h[1] - 1;
var hoursUnitesOutgoing = document.getElementById('hours-unites-' + hoursUnitesOutgoingId);
var hoursUnites = document.getElementById('hours-unites-' + h[1]);
hoursDizaines.className = 'number is-active';
hoursDizainesOutgoing.className = 'number outgoing';
hoursUnites.className = 'number is-active';
hoursUnitesOutgoing.className = 'number outgoing';
// am pm
document.getElementById('ampm').innerHTML = '<span>' + ampm + '</span>';
var t = setTimeout(function(){startTime()}, 500);
}
function checkTime(i) {
if (i<10) {i = "0" + i}; // add zero in front of numbers < 10
return i;
}
startTime();
// get the seconds rolling
var today=new Date();
var s=today.getSeconds();
var secondsElement = document.getElementById('seconds');
secondsElement.style.webkitAnimation = 'secondsTick 60s ' + -s + 's infinite linear';
// apparently webkiteAnimationDelay doesn't work properly, i'm probably missing something but this seems to fix it
secondsElement.style.webkitAnimationPlayState = 'running';
secondsElement.style.mozAnimationDelay = -s + 's';
secondsElement.style.mozAnimationPlayState = 'running';
secondsElement.style.msAnimationDelay = -s + 's';
secondsElement.style.msAnimationPlayState = 'running';
secondsElement.style.animationDelay = -s + 's';
secondsElement.style.animationPlayState = 'running';
// get the audio player going
var radio = document.createElement("AUDIO");
radio.setAttribute("src","http://blobfolio.com/codepenfiles/atc-flip-clock/390917_AhWilderness.mp3");
radio.setAttribute("id", "radio-player");
radio.setAttribute("loop", "true");
radioBtn = document.getElementById("radio-btn");
radioBtn.addEventListener("click", function(){
if((' ' + radioBtn.className + ' ').indexOf(' is-active ') > -1){
radioBtn.className = "btn radio-btn";
radio.muted = true;
}
else {
radioBtn.className = "btn radio-btn is-active";
radio.play();
radio.muted = false;
}
});
This Pen doesn't use any external JavaScript resources.