How to make a CSS3 and JavaScript analog clock

1 2 3 4 5 6 7 8 9 10 11 12

This is a "How To" guiding the ones that are interesting in the creation of an analog clock, similar to the one on the left, with CSS3 and jQuery. First of all, I would like to say that this is in no way a useful method of placing an analog clock on your website. It's only meant as an experiment with CSS3. If you do want an analog clock, you could probably use Flash or an image based JavaScript clock.

I used as a reference the Windows 7 sidebar clock, but it's not a perfect copy. I could have added a lot more details to make it look closer to the real one, but it would have made it a lot more difficult to implement.

Internet Explorer (any version) has not been targeted for this experiment due to it's lack of CSS3 support, so don't be surprised if it doesn't work. Making it functional in Internet Explorer would have over-complicated the JavaScript, attempting to make it work with IE's filters. With that out of the way, let's get started.

The HTML

All the styles will be set in the stylesheet later on, so don't bother with it for now. You can see there are a lot of tags that make the clock very heavy. That's why this is not a good way to create an analog clock for use on your website.

The div#clock will hold everything together. The div.hour-marks holds all the numbers and hour marks. We could have done without it, but it's good to have some sort of container just for those. The next 3 divs are the clock handles (hours, minutes, seconds). The last span is the round circle in the center of the clock.

<div id="clock">
 <div class="back"></div>

 <div class="hour-marks">
  <span class="mark m1"></span>
  <span class="mark m2"></span>
  <span class="mark m3"></span>
  <span class="mark m4"></span>
  <span class="mark m5"></span>
  <span class="mark m6"></span>
  <span class="mark m7"></span>
  <span class="mark m8"></span>
  <span class="mark m9"></span>
  <span class="mark m10"></span>
  <span class="mark m11"></span>
  <span class="mark m12"></span>
  <span class="hour h1">1</span>
  <span class="hour h2">2</span>
  <span class="hour h3">3</span>
  <span class="hour h4">4</span>
  <span class="hour h5">5</span>
  <span class="hour h6">6</span>
  <span class="hour h7">7</span>
  <span class="hour h8">8</span>
  <span class="hour h9">9</span>
  <span class="hour h10">10</span>
  <span class="hour h11">11</span>
  <span class="hour h12">12</span>
 </div>

 <div class="hour-handle"><span class="handle"></span></div>
 <div class="minute-handle"><span class="handle"></span></div>
 <div class="seconds-handle"><span class="handle"></span></div>

 <span class="center"><span></span></span>
</div>

The CSS

Oh man, this is a lot of CSS for something so trivial. Let's try to lay it out.

We're going to start with our clock div, or better yet, div#clock and standard CSS. I gave it a width and height of 200px, but you can change that to whatever you like. Take note however that you will need to modify the position of the dandles and marks also. Actually you will need to modify pretty much everything. Position:relative will allow us to position everything else inside it with position:absolute.

div#clock{
 width: 200px;
 height: 200px;
 position: relative;
 }

Now for the fun part. We don't need a rectangular clock. That would look unattractive. Instead we will make it round with the border-radius feature in CSS3. This allows you to make the corners of a box element round. But if you take it all the way up, that box will turn into a circle. For that you need to specify at least half of the width or height, in this case 100px. This works best for squares as it creates a perfect circle. The first rule is the standard CSS3 declaration. This is used by Opera also. The next one is the proprietary declaration for Gecko based browsers (Firefox, Flock) and the last, but not least, is the proprietary declaration for Webkit based browsers (Safari, Chrome).

div#clock{
 border-radius: 100px;
 -moz-border-radius: 100px;
 -webkit-border-radius: 100px;
 }

To make it look a little nicer, we'll add a gradient for the background. First the standard CSS background. Opera will use this as it does not have a linear gradient method implemented yet. The second one is for Mozilla and the third for Webkit.

div#clock{
 background: #3a3937;
 background: -moz-linear-gradient(right 240deg, #3a3937, #1b1d1c);
 background: -webkit-gradient(linear, right top, left bottom, from(#3a3937), to(#1b1d1c));
 }

Now we're adding a drop-shadow around our clock, just to make it stand out a bit. This can be changed to look like a halo on a dark background. The color can be changed and also the size of the shadow.

div#clock{
 box-shadow: 0 0 10px #666;
 -moz-box-shadow: 0 0 10px #666;
 -webkit-box-shadow: 0 0 10px #666;
 }

These methods will be used throughout the stylesheet, so there's no point in describing each of them. Here's some more of the CSS:

div#clock div.back{
 width: 184px;
 height: 184px;
 position: absolute;
 top: 8px;
 left: 8px;

 border-radius: 92px;
 -moz-border-radius: 92px;
 -webkit-border-radius: 92px;

 background: #fffdf4;
 background: -moz-linear-gradient(top 260deg, #fffdf4, #e2dfce);
 background: -webkit-gradient(linear, center top, center bottom, from(#fffdf4), to(#e2dfce));

 box-shadow: inset 0 0 5px #000;
 -moz-box-shadow: inset 0 0 9px #000;
 -webkit-box-shadow: inset 0 0 9px #000;
}
div#clock div.hour-marks span{
 display: block;
 position: absolute;
}
div#clock div.hour-marks span.mark{ background: #333; width: 8px; height: 3px;}
div#clock div.hour-marks span.hour{
 font-size: 14px;
 text-align: center;
 font-family: Helvetica, Arial, sans-serif;
 color: #444;
}
div#clock span.center,div#clock span.center span{
 position: absolute;
 top: 95px;
 left: 95px;
 background: #333;
 width: 10px;
 height: 10px;

 border-radius: 5px;
 -moz-border-radius: 5px;
 -webkit-border-radius: 5px;
}
div#clock span.center span{ width: 6px; height: 6px; top: 2px; left: 2px; background: #666;}

In order to rotate our hour marks so they face towards the center of the clock, we will be using -*-transform: rotate(). This rotates the element by a specific number of degrees. Since we have 12 hours and a circle has 360 degrees, each mark will be rotated at 30 degree intervals. The positioning of these marks are more of a guess. I didn't feel like finding a method of calculating where each of them should go on a circle. So I positioned them by eye.

div#clock div.hour-marks span.m1 {-moz-transform: rotate(-60deg); -webkit-transform: rotate(-60deg); -o-transform: rotate(-60deg); top:  22px; right:  52px;}
div#clock div.hour-marks span.m2 {-moz-transform: rotate(-30deg); -webkit-transform: rotate(-30deg); -o-transform: rotate(-30deg); top:  52px; right:  22px;}
div#clock div.hour-marks span.m3 {-moz-transform: rotate(0deg);   -webkit-transform: rotate(0deg);   -o-transform: rotate(0deg);   top: 100px; right:   8px;}
div#clock div.hour-marks span.m4 {-moz-transform: rotate(30deg);  -webkit-transform: rotate(30deg);  -o-transform: rotate(30deg);  top: 146px; right:  22px;}
div#clock div.hour-marks span.m5 {-moz-transform: rotate(60deg);  -webkit-transform: rotate(60deg);  -o-transform: rotate(60deg);  top: 176px; right:  54px;}
div#clock div.hour-marks span.m6 {-moz-transform: rotate(90deg);  -webkit-transform: rotate(90deg);  -o-transform: rotate(90deg);  top: 188px; right:  95px;}
div#clock div.hour-marks span.m7 {-moz-transform: rotate(120deg); -webkit-transform: rotate(120deg); -o-transform: rotate(120deg); top: 176px; right: 140px;}
div#clock div.hour-marks span.m8 {-moz-transform: rotate(150deg); -webkit-transform: rotate(150deg); -o-transform: rotate(150deg); top: 146px; right: 170px;}
div#clock div.hour-marks span.m9 {-moz-transform: rotate(180deg); -webkit-transform: rotate(180deg); -o-transform: rotate(180deg); top: 100px; right: 184px;}
div#clock div.hour-marks span.m10{-moz-transform: rotate(210deg); -webkit-transform: rotate(210deg); -o-transform: rotate(210deg); top:  52px; right: 170px;}
div#clock div.hour-marks span.m11{-moz-transform: rotate(240deg); -webkit-transform: rotate(240deg); -o-transform: rotate(240deg); top:  22px; right: 140px;}
div#clock div.hour-marks span.m12{-moz-transform: rotate(270deg); -webkit-transform: rotate(270deg); -o-transform: rotate(270deg); top:  10px; right:  95px;}

div#clock div.hour-marks span.h1 { top:  27px; right:  62px;}
div#clock div.hour-marks span.h2 { top:  50px; right:  35px;}
div#clock div.hour-marks span.h3 { top:  90px; right:  20px; font-weight: bold; font-size: 16px}
div#clock div.hour-marks span.h4 { top: 130px; right:  35px;}
div#clock div.hour-marks span.h5 { top: 153px; right:  62px;}
div#clock div.hour-marks span.h6 { top: 163px; right:  95px; font-weight: bold;font-size: 16px}
div#clock div.hour-marks span.h7 { top: 153px; right: 132px;}
div#clock div.hour-marks span.h8 { top: 130px; right: 160px;}
div#clock div.hour-marks span.h9 { top:  90px; right: 170px; font-weight: bold;font-size: 16px}
div#clock div.hour-marks span.h10{ top:  50px; right: 160px;}
div#clock div.hour-marks span.h11{ top:  27px; right: 132px;}
div#clock div.hour-marks span.h12{ top:  20px; right: 100px; font-weight: bold;font-size: 16px}

The handles are also rotated using CSS3 and JavaScript. To make them rotate around a certain axis, we need to set the transformation origin. If we don't do that, they would just spin in one place, like the needle on a compass.

div#clock div.hour-handle, div#clock div.minute-handle, div#clock div.seconds-handle{
 height: 55px;
 width: 6px;
 position: absolute;
 top: 45px;
 left: 97px;
 overflow: hidden;

 -moz-transform-origin: 50% 100%;
 -webkit-transform-origin: 50% 100%;
 -o-transform-origin: 50% 100%;
}
div#clock div.minute-handle{ height: 80px; top: 20px; width: 4px}
div#clock div.seconds-handle{ height: 80px; top: 20px; left: 100px; width: 1px;}

The color for the handles is given by the inside span.handle. This will also suffer some transformations, in order to become pointed towards one end. In this case we will skew them along the Y axis by a huge amount. The number of degrees indicates the angle at which the skewing is make. This increases the height of the handle, but it's parent container has overflow:hidden and the only part that we can see is the one that we nee: a nice sharp clock handle.

div#clock div.hour-handle .handle, div#clock div.minute-handle .handle, div#clock div.seconds-handle .handle{
 display: block;
 background: #333;
 width: 180%;
 height: 100%;

 -moz-transform: skewY(-84deg);
 -webkit-transform: skewY(-84deg);
 -o-transform: skewY(-84deg);
}
div#clock div.minute-handle .handle{
 -moz-transform: skewY(-86deg); 
 -webkit-transform: skewY(-86deg); 
 -o-transform: skewY(-86deg);
}
div#clock div.seconds-handle .handle{
 -moz-transform: skewY(-88deg); 
 -webkit-transform: skewY(-88deg); 
 -o-transform: skewY(-88deg); 
 background: #f00;
}

That's about all the CSS required for our analog clock.

The JavaScript - jQuery, what else?

After loading the jQuery framework (1.4.2 in this case, but older versions might work) we can add the JavaScript required for the clock to function. It does this by repeating a function every second with the help of setInterval(). Read the comments below for more information. The position / angle of the handles is modified each time the function is run using the same -*-transform: rotate() method described in the CSS.

/* make sure everything is loaded */
$(document).ready(function(){
 /*
 *  this function is run every second to update the clock handles
 */
 function setClock(){
  /* get the handles of the clock */
  var hourHandle = $('div#clock div.hour-handle');
  var minuteHandle = $('div#clock div.minute-handle');
  var secondsHandle = $('div#clock div.seconds-handle');
  /* get the current date from te users computer */
  var now = new Date();

  /* 
  * determine the degrees we need to rotate each handle 
  * we need to create this variable as a string here, before applying it
  */
  var hourDeg = 'rotate(' + ((now.getHours() * 30) + Math.floor(now.getMinutes() / 2)) + 'deg)';
  var minDeg = 'rotate(' + (now.getMinutes() * 6) + 'deg)';
  var secDeg = 'rotate(' + (now.getSeconds() * 6) + 'deg)';

  /* change the CSS for each of the handles */
  hourHandle.css({
   '-moz-transform': hourDeg,
   '-webkit-transform': hourDeg,
   '-o-transform': hourDeg
  });
  minuteHandle.css({
   '-moz-transform': minDeg,
   '-webkit-transform': minDeg,
   '-o-transform': minDeg
  });
  secondsHandle.css({
   '-moz-transform': secDeg,
   '-webkit-transform': secDeg,
   '-o-transform': secDeg
  });
 }

 /* call the function every second */
 setInterval( setClock, 1000);
 });

This is all there is to it. A working example can be seen at the top of this page. I would like to repeat myself: this is not a good way to add an analog clock to your website. It's just a way of showing what can be done with CSS3. Here is the complete code used to make the clock.

The HTML

The CSS

The JavaScript

If you have any comments or questions, please let me know.

3 comments:

Anonymous said...

Nice, thnx for share!

Deepak Sharma said...

Clock is not working

Stelian Andrei said...

@Deepak Sharma: what browser are you using? It works for me on Ubuntu and Firefox 7.0.1, Opera 11.10 and Chrome 13. If you're using Internet Explorer, any version, then you're probably right, it doesn't work. You need a modern browser

Post a Comment