Building an Aesthetic Clock Using JavaScript and CSS ๐
I'll be building a picturesque web clock using JavaScript and CSS. Credits for this idea to Wes Bos on his JavaScript30 course. His content on JavaScript is very interesting, and I recommend you check out his YouTube channel. With that out of the way, let's get coding!
Setup
For this project, I'll be writing all the code in just one file, index.html. The CSS and JS will be internal. I suggest you write his code on a Codepen or a Repl, to understand it better and to be able to use the browser inspection tools. Here's the starter code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JS + CSS Clock</title>
</head>
<body>
<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>
<style>
html {
background: #018DED url(https://unsplash.it/1500/1000?image=881&blur=5);
background-size: cover;
font-family: 'helvetica neue';
text-align: center;
font-size: 10px;
}
body {
margin: 0;
font-size: 2rem;
display: flex;
flex: 1;
min-height: 100vh;
align-items: center;
}
.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);
}
.clock-face {
position: relative;
width: 100%;
height: 100%;
transform: translateY(-3px);
}
.hand {
width: 50%;
height: 6px;
background: black;
position: absolute;
top: 50%;
}
</style>
<script>
const secondHand = document.querySelector('.second-hand');
const minsHand = document.querySelector('.min-hand');
const hourHand = document.querySelector('.hour-hand');
</script>
</body>
</html>
For the hands of the clock, we're using three divs with appropriate class names, and selecting those elements in the js using those class names. If you open index.html in your browser right now, you'll see that all three divs overlap each other. We need to do the following:
Make sure they all start at 12 o'clock.
Make sure that their transition during movement has good timing.
Make sure it has a 'tick' effect, rather than an absolutely smooth animation.
Let's edit the CSS to make this happen.
CSS
Change the .hand
div to have the following styling:
.hand {
width: 50%;
height: 6px;
background: black;
position: absolute;
top: 50%;
transform-origin: 100%;
transform: rotate(90deg);
transition: all 0.05s;
transition-timing-function: cubic-bezier(0.1, 2.7, 0.58, 1);
}
With this code, we're achieving what we mentioned previously. transform-origin: 100%;
sets the rotation point of our hand to be the point on the far right, rather than the centre (the default value is transform-origin: 50%;
). We're setting their default position to be 12 o'clock with transform: rotate(90deg);
. With transition: all 0.05s
we're setting a smooth transition in their movement and the 'tick' effect is created with transition-timing-function: cubic-bezier(0.1, 2.7, 0.58, 1);
. If you open up your browser's dev tools, you'll probably get an option to dynamically change the value of the cubic-bezier
function in the CSS. Try experimenting with some other values to see what the tick looks like!
Great styling, now scripting.
JavaScript
We already have our querySelector()
for all three hands. What we need now is their movement every second. Let's set up a really simple interval first (right after our selectors):
function setDate() {
console.log('log')
}
setInterval(setDate, 1000)
Great, we're logging 'log'. Let me show you how we can make our second's hand move:
function setDate() {
const now = new Date();
const seconds = now.getSeconds();
const secondsDegrees = ((seconds / 60) * 360) + 90;
secondHand.style.transform = `rotate(${secondsDegrees}deg)`;
}
Try it out in your code. It works. Well, obviously it does.
Why though? We're first getting the number of seconds that have passed in this minute in the seconds
variable. Then, we calculate the number of degrees we need to rotate our hand by. We can multiply the fraction of the minute passed by 360, and then add 90 (for that initial rotation from 9 o'clock to 12 o'clock). Finally, we just set the transform
property.
I urge you to try and implement this code for the minute's hand and the hour's hand. That's how you get better, by practising.
This is the final setDate
function:
function setDate() {
const now = new Date();
const seconds = now.getSeconds();
const secondsDegrees = ((seconds / 60) * 360) + 90;
secondHand.style.transform = `rotate(${secondsDegrees}deg)`;
const mins = now.getMinutes();
const minsDegrees = ((mins / 60) * 360) + ((seconds/60)*6) + 90;
minsHand.style.transform = `rotate(${minsDegrees}deg)`;
const hour = now.getHours();
const hourDegrees = ((hour / 12) * 360) + ((mins/60)*30) + 90;
hourHand.style.transform = `rotate(${hourDegrees}deg)`;
}
For hourDegrees
, we're diving the current hours by 12 and not 60 to get the appropriate fraction. That's it! If you haven't understood the code, I'll help you in the comments, so don't refrain from asking.
Thanks for reading! I'm hoping you enjoyed this article, in which case you should click the favourite button. I really appreciate any feedback, positive or negative, so please write a helpful comment too!
Subscribe to my newsletter
Read articles from Shivank Mitra directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Shivank Mitra
Shivank Mitra
Full Stack JavaScript Dev ๐จโ๐ป Basketball Player ๐ Always improving ๐ฏ