I’ve previously demonstrated an analog clock made with SVG and JavaScript, which I thought used a particularly elegant technique. While it’s possible to create the clock movement with , CSS transforms and , it’s not possible to set such a clock to the correct time for the user. To do that, we need JavaScript… and if we’re starting with that, it made sense to experiment with the Web Animation API, showing that it too can use steps() animation for the second hand. (Due to the newness of the Web Animation API, this demo will currently only work in Chrome and Firefox).

Markup & CSS

The markup consists of a <div> with three <span> elements inside it:

<div id="clock">
  <span id="minutehand"></span>
  <span id="hourhand"></span>
  <span id="secondhand"></span>
</div>

The attached styles:

#clock {
  width: 30vw; height: 30vw;
  border-radius: 50%;
  border: 5px double #333;
  background: radial-gradient(#333, #000);
  margin: 2rem auto;
  position: relative;
}
#hourhand, #minutehand, #secondhand {
  position: absolute;
  background: white;
  transform-origin: bottom center;
  box-shadow: 0 0 4px 4px rgba(0, 0, 0, 0.3);
}

The hands are absolutely positioned inside the relatively positioned clock, with their transforms centered at the bottom of each hand. The hands are exactly positioned using calc, accounting for their different widths and heights:

#hourhand {
  width: 4%;
  height: 30%;
  left: calc(50% - (4% / 2));
  top: calc(50% - 30%);
}
#minutehand {
  width: 2%;
  height: 40%;
  left: calc(50% - (2% / 2));
  top: calc(50% - 40%);
}
#secondhand {
  width: 1%;
  height: 45%;
  background: red;
  left: calc(50% - (1% / 2));
  top: calc(50% - 45%);
}

The Script

The , added to the bottom of the page:

var d = new Date(),
hands = [secondhand,minutehand,hourhand],
initDeg = [6*d.getSeconds(), 6*d.getMinutes(), 30*(d.getHours()%12) + d.getMinutes()/2];
for (var i = 0; i < hands.length; i++) {
  var stepper = i == 0 ? 60 : 0;
  var animate = hands[i].animate([
    { transform: 'rotate(' + initDeg[i] + 'deg)' },
    { transform: 'rotate(' + (initDeg[i] + 360) + 'deg)' }
  ], {
    duration: 1000 * Math.pow(60, i + 1),
    easing: 'steps(' + stepper + ', start)',
    iterations: Infinity
  });
}

A quick explanation:

  • d grabs the current date
  • hands is an array of the clock hand ids
  • initDeg creates an array of the current time - hours, minutes and seconds - converted into degrees.
  • the for loop goes through the entire array, incrementing the variable i
  • If i is 0, the variable stepper is set to 60 using a ternary operator.
  • the Web Animation API transforms each of the hands from their initial orientation (i.e. the current time) to 360° from this position; the duration is determined (in milliseconds) by multiplying 60 to the power of i + 1.
  • if stepper is 60, that value is used for steps(); since only the second hand will have this quality, it “ticks” in the animation. The other clock hands receive steps(0), effectively creating linear animation for them.

While it’s written in JavaScript, the animation still isn’t super precise, so please don’t depend on this clock for your personal schedule!

Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/WwPzZX