Skip to content

An analogue clock using only CSS

Hav­ing read the blurb around Safari’s CSS tran­si­tions I opted to famil­iar­ize myself with a quick project — the aim of which was to cre­ate a func­tional, CSS only, ana­logue clock.

Result

Exper­i­ment: CSS Ana­logue Clock
Exper­i­ment works in Safari 4 Beta and Google Chrome. A work­ing clock that option­ally resorts to JavaScript to grab the cur­rent time (can be achieved by other means).

How To

Before get­ting into the nitty gritty I cre­ated four images, a clock face and three trans­par­ent PNG hands (sec­onds, min­utes and hours), ensur­ing that each of these were the same size so that when over­layed their cen­tres would align. The HTML and CSS to get us going is as follows:

<div id="clock">
	<div id="hour"><img src="images/hourHand.png" /></div>
	<div id="minute"><img src="images/minuteHand.png" /></div>
	<div id="second"><img src="images/secondHand.png" /></div>
</div>
#clock {
position: relative;
width: 378px;
height: 378px;
background-image: url('../images/clockFace.png');
left: 50%;
margin: 5em 0 0 -189px;
}

#clock div {
position: absolute;
}

The magic that rotates the clock’s hands comes via two WebKit spe­cific CSS prop­er­ties, -webkit-transition (doc­u­men­ta­tion) and -webkit-transform (doc­u­men­ta­tion). The trans­form prop­erty can alter the appear­ance of an ele­ment via a two dimen­sional trans­for­ma­tion, for instance: scal­ing, rotat­ing and skew­ing a DIV ele­ment. In this case it is used to rotate the clock hands to the cor­rect angles; the CSS below puts the hour hand at 3 o’clock:

#clock img[src*='hour'] {
-webkit-transform: rotate(90deg);
}

The tran­si­tion prop­erty cre­ates an ani­ma­tion of a spec­i­fied prop­erty between two val­ues when trig­gered, for instance fad­ing the opac­ity on a DIV ele­ment from 1 to 0 — trig­gered using the :hover pseudo class. Tran­si­tion dura­tion and the tran­si­tion tim­ing func­tion (e.g. lin­ear) should also be set, amongst other optional prop­er­ties. In this exam­ple the tran­si­tion is from one trans­for­ma­tion angle to another with dura­tions that match the appro­pri­ate clock hand, so the sec­ond hand takes 60 sec­onds to com­plete a 360 degree rota­tion. The tran­si­tion is trig­gered using the :tar­get pseudo ele­ment — if the URI con­tains the ‘clock’ frag­ment then the time piece shall start ticking.

#clock img[src*='second'] {
/* -webkit-transition: property duration timing-function */
-webkit-transition: -webkit-transform 60s linear;
}

#clock:target img[src*='second'] {
-webkit-transform: rotate(360deg);
}

The above tran­si­tion lasts only one rota­tion but by alter­ing the dura­tion length and degree of rota­tion in accor­dance the sec­ond hand can keep on going (e.g. 600 sec­onds and 3600 degrees rota­tion gives a bat­tery life of 10 min­utes), a fairly safe assump­tion that users will not stay on the page for too long.

#clock img[src*='second'] {
-webkit-transition: -webkit-transform 600000s linear;
}

#clock:target img[src*='second'] {
-webkit-transform: rotate(3600000deg);
}

#clock img[src*='minute'] {
-webkit-transition: -webkit-transform 360000s linear;
}

#clock:target img[src*='minute'] {
-webkit-transform: rotate(36000deg);
}

Grab the cur­rent time

Although the ani­ma­tion works beau­ti­fully, CSS alone is not capa­ble of obtain­ing the cur­rent time. To start the clock at the cor­rect time a dynamic trans­for­ma­tion needs to be applied to the clock hand con­tain­ers, this is eas­i­est done with inline styles and can be set in any num­ber of ways by the back­end when the page loads, thereby erad­i­cat­ing any need for JavaScript.

Alter­na­tively, if you’ve no objec­tions to using JavaScript, I’ve cre­ated a small startClock() func­tion to do the job (albeit using Pro­to­type 1.6.0.3 for my own con­ve­nience):

function startClock() {
	var angle = 360/60;
	var date = new Date();
	var hour = date.getHours();
	if(hour > 12) {
		hour = hour - 12;
	}
	var minute = date.getMinutes();
	var second = date.getSeconds();
	var hourAngle = (360/12)*hour + (360/(12*60))*minute;
	$('minute').setStyle('-webkit-transform: rotate('+angle*minute+'deg)');
	$('second').setStyle('-webkit-transform: rotate('+angle*second+'deg)');
	$('hour').setStyle('-webkit-transform: rotate('+hourAngle+'deg)');
}

A word of warn­ing — apply­ing the inline style directly to the image will over­ride the tran­si­tion effects defined in the CSS file.

Paul Hayes Paul Hayes is a developer at Last.fm. You should follow him on Twitter, where he talks about UX, HTML, CSS and JavaScript, amongst other cool stuff.

22 Comments

  1. Jose

    In Google Chromium (for linux) works fine!

  2. John Giotta

    You can add Google Chrome to your com­pat­i­ble browsers

  3. Dever

    Works in Safari 3.2.1 on a Mac, cool !

  4. david
  5. Mem's

    This work also on Safari 3.1.2 (525.21)

  6. Scavenger

    Cool!

    Page zoom­ing doesn’t work on Mac (Safari 3.2.1), though.

  7. Zachary Abresch

    Sweet! Works in Safari 4 BETA. I’m going to try this out myself!

  8. James Urquhart
  9. Val

    Very cool! Gotta be care­ful with this stuff, tho — when I ran it in Chrome on WinXP on a Dell Insp­iron 6000, it chewed up 55% of CPU.

  10. wilq32

    You could try to inte­grate rotat­ing for older browsers by using: http://​wilq32​.googlepages​.com/​w​i​l​q​3​2​.​r​o​l​l​i​m​a​ge222

  11. Ryan Cannon

    I used a sim­i­lar tech­nique here:

    http://​ryan​can​non​.com/​m​t​g/hi/

    to keep time, but mine is intended for longer peri­ods. One thing to note: you must always incre­ment the trans­form up. If, for exam­ple, you set the hands at noon to 0deg when they were at 359deg a minute before hand, your arms will rotate backwards.

    A bit of a pain, and I haven’t found a work around, other than incre­ment­ing to infinity.

  12. Matt

    You get an inter­est­ing effect when you try and select the image in chrome, crazy shapes!

  13. Ben

    This is amaz­ing! Had no idea you could do any­thing like this in CSS, will have to give it a go!

  14. Anoop Kumar Pandey

    I saw the source code of demo page that con­tains the link ‘start’ to start the clock but How to start the clock auto­mat­i­cally on page load ?? Plz mail me.…

  15. ghislaine

    Hello,

    This is so inter­est­ing!! Sorry for my bad eng­lish, i am french and i did a trans­la­tion of this page in my blog.
    Is it ok for you? I mean you allow me to share what i under­stand with oth­ers.
    Here is the link : http://​www​.ghis​laine​-wab​ste​mer​.com/​2​0​1​1​/​0​1​/​t​r​o​u​v​a​i​l​l​e​s​-​w​a​b​s​t​emer/
    thanks,

  16. Cgbaran

    Very cre­ative nice work;)

  17. ramesh

    i go through the tuto­r­ial but clock is not work­ing…
    can you help me on that…

  18. Mattias

    It isnt work­ing in lat­est chrome, help?

  19. Emre ACAR

    how can I do start the clock with­out url : “clock.html#clock” –> I want to url only clock.html not #clock ? how can we doing ?

  20. Tyson Reed

    i have a project i’m look­ing for a devel­oper for, which involves devel­op­ment of ana­logue clocks with some fea­tures a lit­tle beyond your exam­ple here… its for the play­back on SIg­nage Media play­ers… are you avail­able for free­lance work…?

  21. Wang

    very beau­ti­ful!

  22. Biju

    Ctrl+A and you can see the image rotating