Building a Pure JavaScript and CSS Clock with Keyframe Animation and Animation‑Delay
This tutorial explains how to create a functional analog clock using only HTML, CSS, and a small amount of JavaScript by leveraging CSS keyframe animations, animation‑delay (including negative values), and basic layout techniques such as border‑radius, box‑shadow, and absolute positioning.
This article introduces a challenge from Wes Bos' JavaScript30 series that asks you to build an analog clock using only pure JavaScript and CSS, without any frameworks, libraries, or compilers.
JavaScript30 provides 30 free video tutorials, challenge starter files, and solution source code to help developers practice vanilla JavaScript.
The clock consists of a simple HTML structure, basic CSS styling, CSS keyframe animation, and a tiny JavaScript snippet that synchronizes the animation with the current time.
Key Knowledge Points
HTML structure and basic CSS
CSS keyframe animation
JS control of
animation-delayHTML Structure and Basic CSS
The clock's HTML is straightforward:
<div class="clock">
<div class="clock-face">
<div class="hand hour-hand"></div>
<div class="hand min-hand"></div>
<div class="hand second-hand"></div>
</div>
</div>The .clock element forms the outer circle, while .clock-face holds the three hands. A circular border is created with border-radius:50% and refined with box-shadow.
.clock {
width: 30rem;
height: 30rem;
border: 20px solid white;
border-radius: 50%;
margin: 50px auto;
position: relative;
padding: 2rem;
box-shadow: 0 0 0 4px rgba(0,0,0,0.1),
inset 0 0 0 3px #EFEFEF,
inset 0 0 10px black,
0 0 10px rgba(0,0,0,0.2);
}The inner panel positions the hands and adds a central dot using the .clock-face:after pseudo‑element.
.clock-face {
position: relative;
width: 100%;
height: 100%;
transform: translateY(-3px); /* account for hand height */
}
.clock-face:after {
width: 1em;
height: 1em;
left: 50%;
top: 50%;
position: absolute;
content: '';
background-color: #a8c5d1;
border-radius: 50%;
box-shadow: 0 0 0 2px rgba(0,0,0,0.1),
0 0 10px rgba(0,0,0,0.2);
transform: translate(-50%, -50%);
}All hands share the .hand base style; specific adjustments give each hand its shape and color.
.hand {
width: 50%;
height: 6px;
background: black;
position: absolute;
top: 50%;
transform-origin: 100%;
transform: rotate(90deg);
box-shadow: 0 0 0 0.1px #fff,
0 0 0 1px rgb(0 0 0 / 10%),
0 0 8px rgb(0 0 0 / 50%),
2px 4px 1px rgb(0 0 0 / 50%);
}
.second-hand {
height: 3px;
background-color: #ff0e0e;
border-bottom-left-radius: 100%;
border-top-left-radius: 100%;
}
.min-hand {
background-color: white;
width: 45%;
left: 5%;
}
.hour-hand {
background-color: white;
border-radius: 5px;
width: 40%;
height: 12px;
left: 10%;
}CSS Keyframe Animation
A simple @keyframes rule rotates an element one full turn plus the initial 0.25 turn offset (90°) required for the hands to start at 12 o’clock.
@keyframes circle {
to { transform: rotate(1.25turn); }
}The animation is applied to each hand with different durations and timing functions.
.second-hand { animation: circle 60s steps(60, end) infinite; }
.min-hand { animation: circle 3600s linear infinite; }
.hour-hand { animation: circle 43200s linear infinite; }The second hand uses steps(60, end) to create a ticking effect.
JS Controlling animation-delay
By setting a negative animation-delay equal to the elapsed time since midnight, the clock starts at the actual current time without further JavaScript updates.
const secondHand = document.querySelector('.second-hand');
const minsHand = document.querySelector('.min-hand');
const hourHand = document.querySelector('.hour-hand');
function init() {
const now = new Date();
const seconds = now.getSeconds();
secondHand.style.animationDelay = `-${seconds}s`;
const mins = now.getMinutes() * 60 + seconds;
minsHand.style.animationDelay = `-${mins}s`;
const hours = now.getHours() * 3600 + mins;
hourHand.style.animationDelay = `-${hours}s`;
}
init();After this initialization, the CSS animation runs independently, keeping the clock synchronized.
Summary
✔️ Use border-radius:50% for a circular clock face. ✔️ Apply box-shadow for visual depth. ✔️ Center elements with position:absolute and transform: translate(-50%, -50%). ✔️ Create sharp hand tips using border-bottom-left-radius:100%; border-top-left-radius:100%. ✔️ Animate hands with @keyframes and appropriate durations. ✔️ Synchronize the clock to real time by setting a negative animation-delay via JavaScript.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
