This is

Ben's Blog

Creating a digital watch in pure CSS

Off the back of last week’s pure CSS clock, I decided to stick with the horological theme and have a crack at creating a digital watch face in pure CSS. Turns out making the digital numbers was a little easier (and perhaps a little more fun) than creating the clock (although I still think the clock is a little more interesting). I hadn’t intended to go the whole hog and make the watch as well, but one kinda followed the other. If you haven’t seen it yet, you can find it here.

Starting with the digits

First thing I need to do was draw out my digit and figure out how to replicate it in CSS. As you can see, it’s created in a four by seven grid.

8

Firstly I created a box 400 by 700 pixels in size. This is the container for each individual digit. Each notch in the digit is exactly the same size and shape, so we just need to create one and then rotate and reposition it. Let’s look at the CSS:

.number {
	float: left;
	width: 100px;
	height: 175px;
	display: block;
	position: relative;
	-webkit-transform: skew(-5deg,0);
		    transform: skew(-5deg,0);
}
	.notchContainer {
		position: absolute;
		width: 100%;
		height: 14.2857142857%;
		background-color: transparent;
	}
		.notchBG {
			background-color: #949782;
			-webkit-animation-iteration-count: infinite;
					animation-iteration-count: infinite;
		}
			.notch {
				position: absolute;
				top: 10%;
				left: 25%;
				width: 50%;
				height: 80%;
				background: inherit;
				-webkit-transition: background-color 100ms linear;
				transition: background-color 100ms linear;
			}
				.notchEnd {
					background: inherit;
					-webkit-transition: background-color 100ms linear;
					transition: background-color 100ms linear;
					position: absolute;
					width: 14.1421356237%;
					height: 56.5685424949%;
					display: block;
					-webkit-transform:rotate(45deg);
					-webkit-transform-origin: 0% 0%;
				        transform:rotate(45deg);
				        transform-origin: 0% 0%;				
				}
				.notchEndTop {
					top: 10%;
					left: 25%;
				}
				.notchEndBtm {
					top: 10%;
					left: 75%;
				}

	.notchVertical {
		-webkit-transform:rotate(90deg);
		-webkit-transform-origin: 0% 0%;
		        transform:rotate(90deg);
			    transform-origin: 0% 0%;
	}
	.notchA {
		top: 0;
		left: 0;
	}
	.notchB {
		top: 0;
		left: 25%;
	}
	.notchC {
		top: 0;
		left: 100%;
	}
	.notchD { /* 30 * 1.42857142857 */
		top: 42.8571428571%;
		left: 0;
	}
	.notchE {
		top: 42.8571428571%;
		left: 25%;
	}
	.notchF {
		top: 42.8571428571%;
		left: 100%;
	}
	.notchG { /* 60 * 1.42857142857 */
		top: 85.7142857142%;
		left: 0;
	}

Everything is contained in an element with the class ‘number’. As you can see in the code above, the sizes have been changed slightly – as everything contained in the number is sized and positioned with percentages, you can resize the number to whatever you’d like – as long as it follows the rules of 4 and 7 (so 40/70, 60/105, etc).

Each notch is created inside a notch container, as seen below:

<div class="notchA notchContainer">
	<div class="notchBG">
		<div class="notch"></div>
		<div class="notchEnd notchEndTop"></div>
		<div class="notchEnd notchEndBtm"></div>
	</div>
</div>

Each notch has a class of A-G that determines the position within the number, and we can apply the ‘notchVertical’ class to the notch in order to rotate it 90 degrees. There are three elements inside the notch that are actually displayed on screen. These are a rectangle and two squares rotated 45 degrees in order to create the hexagon. I created the hexagon using 3 shapes rather than the CSS shapes method (see here for a good description) because the shapes method uses borders that need a pixel based width, and we want to use percentages so we can resize it easily. Because we’re colouring these elements with a background colour, we can also recolour them much more easily in our animation.

The 45 degree rotated squares are sized using some maths so the corner to corner length is the same as the height of the notch on it’s side. All 3 elements are wrapped in another class called ‘notchBG’. This class has absolutely no layout – cheekily we’re using it in the animation to set the background colour of the elements it contains (you’ll see their background are set to inherit).

The other thing to note is the notch and the notch ends have a CSS transition on the background colour set at 100ms. When we animate the number, this will very, very quickly fade the background colour, giving it that old-school look cheap watches had as the number switched to the next one.

Animating the digits

Next we need to make a digit count. I started by writing out all the positions for every notch on a 0-9 count:

    0123456789

 -  1011011111  A
|   1000111011  B
  | 1111100111  C
 _  0011111011  D
|   1010001010  E
  | 1101111111  F
 _  1011011010  G

As you can see, each is determined by an on or off. 0-9 is the easiest to do, because 10 seconds is all ten positions, and 10 goes into 100 easily. So we can write some keyframe animation to switch the notchBG class from on to off (change it’s colour) like this:

	@keyframes notchA {
	    0%  { background-color: #21230e; }
	    10% { background-color: #949782; }
	    20% { background-color: #21230e; }
	    40% { background-color: #949782; }
	    50% { background-color: #21230e; }
	}

And animate it like this, with a step amount, and a duration for the animation. This one is for the 0-6 count second digit:

#secondA .notchA .notchBG {
	-webkit-animation-timing-function: steps(1);
	animation-timing-function: steps(1);
	-webkit-animation-duration: 60s;
	animation-duration: 60s;
}

#secondA .notchA .notchBG {
	-webkit-animation-name: notchA6;
	animation-name: notchA6;
}

Obvious you need to repeat this for all the other notches (have a look in the code)! We can use the 0-9 count for the second tick and the minute count. But we also need to create a 0-6 count, a 0-2 count and a 0-23 count. This covers all animation across all the digits in a digital display. The other numbers are a little harder to do because the animation relies on a percentage. Here’s the 0-6 count on another notchA:

	@keyframes notchA6 {
	    0%  { background-color: #21230e; }
	    16.66666666666666666666666666667% { background-color: #949782; }
	    33.33333333333333333333333333333% { background-color: #21230e; }
	    66.66666666666666666666666666667% { background-color: #949782; }
	    83.33333333333333333333333333333% { background-color: #21230e; }
	}

You’ll see I’ve had to work out timing but diving 100 by 6, and then multiplying it up. Similarly this has to be done with 3 and 24. 24 was the toughest – I redrew out all the positions of the notches for all 24 positions (0-9,0-9,0-3), then wrote a quick loop to give me all the percentage amounts for 100/24.

Animating the time

Once all the numbers are in place I animated the time in the same way I did in the pure CSS clock. I get the time server side, work out how many seconds into each animation the clock needs to be, and then drop this into a style tag in the head of the document.

Creating the watch

I won’t describe the entire watch creation here (it’ll go on forever), but I’ll cover a few bits, and if you have any questions I’ll have a go at answering them in the comments.

Firstly, if you look at the code, I created the watch double the size it is now (no real reason other than it seemed easier – and then it was too big), then resized it with a CSS transformation at the end so it’s 50% the size. For some reason this makes the numbers look smoother. It’s also a much more sensible size on my laptop screen ;-)

Everything outside the watch face is created using elements wrapped in elements, with a background colour, and a border. Border radius is used to round the corners. The strap is created with two skewed rectangles, and there’s a few gradients thrown in for good measure.

The button is placed on a low level, and the light effect is placed on a level much higher up, inside a box hidden with display:none and the overflow hidden. If you click the light button, the light div is set to display block. Despite the button element being much further down the tree, we can target the light with:

#lightSwitch:active ~ #light {
	display: block;
}

Finally I wrapped the whole thing in a rounded box and lopped of the ends of the strap. It looks a little neater this way. The text is absolutely positioned, and the ‘illuminated’ bit is skewed to give it the same sort of look as the old Casio watches. Interestingly, this text isn’t very smooth in Chrome, but Firefox renders it nicely. That said, the light works nicely in Chrome, but causes a display flicker in Firefox.

As with the pure CSS clock, this uses an *awful* lot of CPU – its not terribly practical. It works nicely for me on the latest Firefox and Chrome builds on OSX. IE9 is probably shit out of luck, but I suspect IE10 may be ok…

Anyway, here’s a link if you haven’t looked already. Let me know if you like it :-)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

© 2014 Ben's Blog. All rights reserved.