mixin strip(x)
  .strip
    - let i = -1;
    while i++ < x
      .number= i

.clock
  .hr
    +strip(2)
    +strip(9)
  .min
    +strip(5)
    +strip(9)
  .sec
    +strip(5)
    +strip(9)
View Compiled
number-size = 4vmin

lighter = #f9fbfd
light = #dfe6f6
bg = #C4D2EF
dark = #a9bee8
primary = #3e6ccb

neo-thickness = number-size/4


neo-shadow()
  background-color light
  box-shadow:
    -1*neo-thickness -1*neo-thickness 2*neo-thickness -0.5*neo-thickness lighter, 
    neo-thickness neo-thickness 2*neo-thickness dark

*
  box-sizing border-box
  padding 0
  margin 0
  
body
  font-family monospace
  font-size number-size
  min-height 100vh
  display grid
  overflow hidden
  place-items center
  background linear-gradient(-45deg, bg, light)
  
 
.hr, .min, .sec
  display grid
  grid-template-columns 1fr 1fr
  grid-gap number-size
  grid-row 1/2
  align-items start
  
.number
  user-select none
  width number-size*2
  height @width
  display grid
  place-items center
  color lighter
  transition all 500ms 100ms ease
  border-radius 50%
  
  &.pop
    color primary
    font-weight bold
    transform scale(1.3)
    neo-shadow()
  
.strip
  transition transform 500ms ease-in-out
  border-radius (number-size/3)
  neo-shadow()
  
 .clock
   display grid
   grid-template-columns repeat(3, 1fr)
   grid-gap number-size*2
   height number-size
   position relative
   padding 0 number-size
View Compiled
const strips = [...document.querySelectorAll(".strip")];
const numberSize = "8"; // in rem

// highlight number i on strip s for 1 second
function highlight(strip, d) {
  strips[strip]
    .querySelector(`.number:nth-of-type(${d + 1})`)
    .classList.add("pop");

  setTimeout(() => {
    strips[strip]
      .querySelector(`.number:nth-of-type(${d + 1})`)
      .classList.remove("pop");
  }, 950); // causes ticking
}

function stripSlider(strip, number) {
  let d1 = Math.floor(number / 10);
  let d2 = number % 10;

  strips[strip].style.transform = `translateY(${d1 * -numberSize}vmin)`;
  highlight(strip, d1);
  strips[strip + 1].style.transform = `translateY(${d2 * -numberSize}vmin)`;
  highlight(strip + 1, d2);
}

setInterval(() => {
  // get new time
  const time = new Date();

  // get h,m,s
  const hours = time.getHours();
  const mins = time.getMinutes();
  const secs = time.getSeconds();

  // slide strips
  stripSlider(0, hours);
  stripSlider(2, mins);
  stripSlider(4, secs);

  // highlight numbers
}, 1000);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.