CSS/Javascript Word Clock

CSS/Javascript Word Clock
CSS Clock

A little experiment I built: a word clock using CSS3 transforms and a little Javascript to run the actual clock. Useful? Maybe not. Fun? Definitely.

The code behind it is fairly straight-forward. Let's take a peak:

CSS

The first thing we need to do is set a base set of styles for each arm of the clock.

li {
  position: absolute;
  width: 150px;
  text-transform: lowercase;
  -webkit-transform-origin: 0 center;
  -moz-transform-origin: 0 center;
  color: rgba(255, 255, 255, 0.1);
  position: absolute;
  left: 0;
  top: 0;
}

This is basically saying for each arm, position it at the top of the clock body, and then rotate around left side, so that we have uniform rotations.

Then, for each arm, we set the actual rotation. Here is the HTML for the "hour" arms:

<ol id="hours">
  <li><span>One</span></li>
  <li><span>Two</span></li>
  <li><span>Three</span></li>
  <li><span>Four</span></li>
  <li><span>Five</span></li>
  <li><span>Six</span></li>
  <li><span>Seven</span></li>
  <li><span>Eight</span></li>
  <li><span>Nine</span></li>
  <li><span>Ten</span></li>
  <li><span>Eleven</span></li>
  <li><span>Twelve</span></li>
</ol>

And, the corresponding CSS:

#hours > li {
  padding: 0 0 0 80px;
}
#hours > li:nth-child(1) {
  -webkit-transform: rotate(-60deg);
  -moz-transform: rotate(-60deg);
}
#hours > li:nth-child(2) {
  -webkit-transform: rotate(-30deg);
  -moz-transform: rotate(-30deg);
}
#hours > li:nth-child(3) {
  -webkit-transform: rotate(0deg);
  -moz-transform: rotate(0deg);
}
#hours > li:nth-child(4) {
  -webkit-transform: rotate(30deg);
  -moz-transform: rotate(30deg);
}
#hours > li:nth-child(5) {
  -webkit-transform: rotate(60deg);
  -moz-transform: rotate(60deg);
}
#hours > li:nth-child(6) {
  -webkit-transform: rotate(90deg);
  -moz-transform: rotate(90deg);
}
#hours > li:nth-child(7) {
  -webkit-transform: rotate(120deg);
  -moz-transform: rotate(120deg);
}
#hours > li:nth-child(8) {
  -webkit-transform: rotate(150deg);
  -moz-transform: rotate(150deg);
}
#hours > li:nth-child(9) {
  -webkit-transform: rotate(180deg);
  -moz-transform: rotate(180deg);
}
#hours > li:nth-child(10) {
  -webkit-transform: rotate(210deg);
  -moz-transform: rotate(210deg);
}
#hours > li:nth-child(11) {
  -webkit-transform: rotate(240deg);
  -moz-transform: rotate(240deg);
}
#hours > li:nth-child(12) {
  -webkit-transform: rotate(270deg);
  -moz-transform: rotate(270deg);
}

The first line sets the padding, so that each hour arm begins 80px from the center. The rest set up the individual rotations for each arm, at 30 degrees each. The minute and second hands have more padding, and rotate 6 degrees for each arm. The rest of the CSS in the file is used to style the clock, and to show/hide the extra text.

Javascript

All we need to do for the javascript is create a function that sets class="active" on each arm of the current time. So, at 12:45 and 20 seconds, the 12 hour arm, the 45 minute arm, and the 20 second arm have class="active", and the rest are normal. Then we simply set an interval to run every second.

$(function () {
  var hours = $('#hours'),
    minutes = $('#minutes'),
    seconds = $('#seconds');

  //these are default grabs so that the first time it runs, it doesn't throw an error
  //after that, we use them to cache the current active arm for each group, so that we
  //don't have to waste time searching
  var cHour = $('html'),
    cMinute = $('html'),
    cSecond = $('html');

  var setCurrentTime = function () {
    //establish what the time is
    var currentTime = new Date();
    var hour = currentTime.getHours() - 1;
    if (hour == -1) {
      hour = 11;
    }
    var minute = currentTime.getMinutes() - 1;
    if (minute == -1) {
      minute = 59;
    }
    var second = currentTime.getSeconds() - 1;
    if (second == -1) {
      second = 59;
    }
    var ampm = 'am';
    if (hour > 11) {
      ampm = 'pm';
      hour = hour - 12;
    }
    if (hour == 11) {
      ampm = 'pm';
    }

    //remove the active class, and add it to the new time
    cHour.removeClass('active');
    cHour = hours.children(':eq(' + hour + ')').addClass('active');

    cMinute.removeClass('active');
    cMinute = minutes.children(':eq(' + minute + ')').addClass('active');

    cSecond.removeClass('active');
    cSecond = seconds.children(':eq(' + second + ')').addClass('active');

    $('body').removeClass('am').removeClass('pm').addClass(ampm);
  };
  //set the interval to run each second
  setInterval(setCurrentTime, 1000);
});

It's a fun little experiment that doesn't have any real value on it's own, but it's a good exercise and as good of an excuse as any to play around with CSS transforms.

The full CSS file can be found here, and the javascript can be found here

Comments (archived for posterity)

  • Nate Klaiber commented

    That’s just freaking awesome. ha.

  • overcriticalpedant commented

    Very nice demo I must say

    However, can I humbly suggest (as politely as humanly possible) that you make sure your code is cross-browser compatible before accusing browsers you don’t bother supporting that they’re apparently “not up to snuff”.

    Obviously I’m not saying you should have to do overly extensive browser testing for what is simply a proof-of-concept test, but just seeing the “not up to snuff” message is just a tiny tiny bit irksome for anyone visiting your page in the most “up to snuff browser” available (in terms of Transform support)

    A few things:

    1) There are not many CSS vendor prefixes - if you choose to use experimental prefixed properties, putting in a property for each prefix doesn’t take long

    2) Modernizr 1.1 doesn’t provide reliable detection for experimental (prefixed) CSS - you could try getting 1.2 on github - it’s slightly better

    3) unprefixed properties should always be defined last so as not to have them overridden by experimental ones - i.e. put border-radius AFTER -moz-border-radius as when Firefox eventually implements the standard one it will behave more correctly than the experimental one (which will keep old behaviour for compatibility)

    Again, apologies for being critical - it’s intent is purely constructive as this is a REALLY SWEET demo that I’d love to see working properly for everyone

  • Dan Ott commented

    @oc Pendant - Thanks for the thoughts. Constructive criticisms are good!

    The “up to snuff” thing was a last-second addition meant to avoid confusion, and not too well thought out, obviously. I’ll tweak the language and settings. Also, Thanks for letting me know about the Modernizr updated, I’ll check that out pronto.

    I definitely did not include all of the available vendor prefixes, either. I’ll take a look.

    Can I ask what browser you were using, just so I can make sure things are working correctly once I tweak things? I made an assumption that Modernizer would tell me when I could rely on css transform support, but I’ve seen it be wrong before.

    Anyway, thanks.

  • Bruno commented

    This code with a few adjustments would make an absolutelly great countdown clock that would fit very well on teasers and hot sites. Just random thought…

  • Eric Wiley commented

    I think that may be the most attention I’ve every paid to a clock since my Mickey Mouse watch. Thanks for sharing, I really enjoyed it.

  • Josh Walsh commented

    This is really cool. I’ve actually been playing with a concept that’s similar, except that the current values stay fixed in place and the clock rotates around the value. Like a clock where the hands stay still and everything else moves around it.

    Thanks for sharing this.

  • overcriticalpedant commented

    @Dan Ott

    Thanks for the response.

    FYI:

    Vendor-prefixes are listed here: http://www.w3.org/TR/CSS2/syndata.html#vendor-keyword-history

    Of those, -xv- is for xhtml voice only (I see your site is html so that definitely never applies) and most of the rest are non-browsers or outdated, leaving only -o- and -khtml- missing from your list (and -ms- if you absolutely must… )

    The major bug in Modernizr was in it’s vendor-prefix support - they check using simple javascript object detection and were checking for el.mozBorderRadius instead of el.MozBorderRadius (mis-capitalisation) - they’ve since fixed this in 1.2pre.

    I was using the Opera browser - it has the most complete and stable CSS Transforms support as it was added later than Webkit’s and is therefore a better reflection of the current draft of the w3c spec. It’s still not necessarily 100% though as the spec’s not finished.

  • patt commented

    Thought this was feckin cool… any chance getting it as an app for iPhone… I’d give yah 49p…

  • Grenadier commented

    this is very cool !!!

  • Pascal commented

    hello,

    really nice work, it reminds me this one which is not a JS but a designer clock you can buy for 1000$ (sic).

    http://walyou.com/wall-clock-no-numbers-design/

    maybe you could inspire yourself from it for the next gen?

    best regards,

    Pascal

  • Rabii commented

    This is totally amazing man. You can add a feature that can change to white background in day time and black in night time.