HTC Clock

Recreating the HTC clock widget with CSS3 and Javascript

One of the reasons HTC’s phones are so popular right now is their slick interface. The most iconic part of its interface is its clock and weather widget. With the help of some CSS3, we can recreate the whole thing using RGBa transparencies, box-shadows, and gradient backgrounds with multiple color stops. What does this all mean? Well it means like all good things that come with web design, it doesn’t work in IE, however all of the other major browsers work (Chrome, Firefox, Safari, and Opera).

Live Demo

Here’s what we’ll be making:

12 00
Gotham
Mostly cloudy
Mostly cloudy
68°
H: 63°
L: 36°

HTML

<div id="clock">
    <div id="top-gradient"></div>
    <div id="time"><span id="hour">12</span> <span id="mins">00</span></div> <!-- time -->
    <div id="weather">
        <div id="location">Des Moines<br />Mostly cloudy</div>
        <img id="icon" src="img/sun-and-cloud.png" alt="Mostly cloudy" >
        <div id="temp">61°</div>
        <div id="high-low-temps">H: 63°<br />L: 36°</div>
    </div> <!-- weather -->
</div> <!-- clock -->

The only thing to note here is that the empty <div id="top-gradient"> will be used in the lighter portion of the background.

CSS

First, let’s create the semi-transparent black background which will also serve as our container:

#clock {
	background: rgba(0, 0, 0, 0.5);
	border-radius: 10px;
	font-family: Arial, Helvetica, sans-serif;
	height: 220px;
	margin: 0 auto;
	position: relative;
	width: 410px;
	-webkit-box-shadow: 0px 3px 5px rgba(0,0,0,0.5);
	-moz-box-shadow: 0px 3px 5px rgba(0,0,0,0.5);
	box-shadow: 0px 3px 5px rgba(0,0,0,0.5);
}

Using RGBa we set the background to black with 50% transparency. Since this is also our container we set the height and width, set the position: relative so that all of our other elements can be positioned absolutely and do a little extra styling including rounded corners with border-radius and a box-shadow.

Next, we’ll use our empty div to layer another semi-transparent white gradient towards the top half of the box to give it that glossy look

#top-gradient {
	border-radius: 10px;
	border-top: 1px solid rgba(255, 255, 255, 0.7); /* 70% transparent white top border */
	height: 94px;
	position: absolute;
		left: 0;
		top: 0;
	width: 100%;
	background: -moz-linear-gradient(top, rgba(255,255,255,0.5) 0%, rgba(255,255,255,0.1) 100%); /* FF3.6+ */
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,0.5)), color-stop(100%,rgba(255,255,255,0.1))); /* Chrome,Safari4+ */
	background: -webkit-linear-gradient(top, rgba(255,255,255,0.5) 0%,rgba(255,255,255,0.1) 100%); /* Chrome10+,Safari5.1+ */
	background: -o-linear-gradient(top, rgba(255,255,255,0.5) 0%,rgba(255,255,255,0.1) 100%); /* Opera11.10+ */
	background: -ms-linear-gradient(top, rgba(255,255,255,0.5) 0%,rgba(255,255,255,0.1) 100%); /* IE10+ */
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#FFFFFF',GradientType=0 ); /* IE6-9 */
	background: linear-gradient(top, rgba(255,255,255,0.5) 0%,rgba(255,255,255,0.1) 100%); /* W3C */	}

Lately, I’ve been using the Ultimate CSS Gradient Generator a lot and I used it here by creating a solid white to solid white RGBa gradient. Once I copied that code I modified the transparency for each line to start at 10% rgba(255,255,255,0.1) and end at 50% transparency rgba(255,255,255,0.5).

The clock

Time to play with time, the clock portion is styled to look like a modern version of an old flip clock where there is a separation in the middle of the card and you can see several cards lined up behind the current one. This is where most of the work happens for this project.

Be warned this looks like a lot of intimidating code but it’s not as bad as it looks, I’ll explain below:

#hour, #mins {
	color: #000;
	line-height: initial; /* To make the text vertically centered */
	background: rgb(255,255,255); /* Old browsers */
	background: -moz-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(223,223,223,1) 1%, rgba(212,212,212,1) 2%, rgba(239,239,239,1) 3%, rgba(205,205,205,1) 4%, rgba(239,239,239,1) 5%, rgba(205,205,205,1) 47%, rgba(190,190,190,1) 48%, rgba(250,250,250,1) 49%, rgba(194,194,194,1) 93%, rgba(206,206,206,1) 94%, rgba(223,223,223,1) 95%, rgba(202,202,202,1) 96%, rgba(232,232,232,1) 97%, rgba(208,208,208,1) 98%, rgba(255,255,255,1) 100%); /* FF3.6+ */
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,1)), color-stop(1%,rgba(223,223,223,1)), color-stop(2%,rgba(212,212,212,1)), color-stop(3%,rgba(239,239,239,1)), color-stop(4%,rgba(205,205,205,1)), color-stop(5%,rgba(239,239,239,1)), color-stop(47%,rgba(205,205,205,1)), color-stop(48%,rgba(190,190,190,1)), color-stop(49%,rgba(250,250,250,1)), color-stop(93%,rgba(194,194,194,1)), color-stop(94%,rgba(206,206,206,1)), color-stop(95%,rgba(223,223,223,1)), color-stop(96%,rgba(202,202,202,1)), color-stop(97%,rgba(232,232,232,1)), color-stop(98%,rgba(208,208,208,1)), color-stop(100%,rgba(255,255,255,1))); /* Chrome,Safari4+ */
	background: -webkit-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(223,223,223,1) 1%,rgba(212,212,212,1) 2%,rgba(239,239,239,1) 3%,rgba(205,205,205,1) 4%,rgba(239,239,239,1) 5%,rgba(205,205,205,1) 47%,rgba(190,190,190,1) 48%,rgba(250,250,250,1) 49%,rgba(194,194,194,1) 93%,rgba(206,206,206,1) 94%,rgba(223,223,223,1) 95%,rgba(202,202,202,1) 96%,rgba(232,232,232,1) 97%,rgba(208,208,208,1) 98%,rgba(255,255,255,1) 100%); /* Chrome10+,Safari5.1+ */
	background: -o-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(223,223,223,1) 1%,rgba(212,212,212,1) 2%,rgba(239,239,239,1) 3%,rgba(205,205,205,1) 4%,rgba(239,239,239,1) 5%,rgba(205,205,205,1) 47%,rgba(190,190,190,1) 48%,rgba(250,250,250,1) 49%,rgba(194,194,194,1) 93%,rgba(206,206,206,1) 94%,rgba(223,223,223,1) 95%,rgba(202,202,202,1) 96%,rgba(232,232,232,1) 97%,rgba(208,208,208,1) 98%,rgba(255,255,255,1) 100%); /* Opera11.10+ */
	background: -ms-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(223,223,223,1) 1%,rgba(212,212,212,1) 2%,rgba(239,239,239,1) 3%,rgba(205,205,205,1) 4%,rgba(239,239,239,1) 5%,rgba(205,205,205,1) 47%,rgba(190,190,190,1) 48%,rgba(250,250,250,1) 49%,rgba(194,194,194,1) 93%,rgba(206,206,206,1) 94%,rgba(223,223,223,1) 95%,rgba(202,202,202,1) 96%,rgba(232,232,232,1) 97%,rgba(208,208,208,1) 98%,rgba(255,255,255,1) 100%); /* IE10+ */
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#ffffff',GradientType=0 ); /* IE6-9 */
	background: linear-gradient(top, rgba(255,255,255,1) 0%,rgba(223,223,223,1) 1%,rgba(212,212,212,1) 2%,rgba(239,239,239,1) 3%,rgba(205,205,205,1) 4%,rgba(239,239,239,1) 5%,rgba(205,205,205,1) 47%,rgba(190,190,190,1) 48%,rgba(250,250,250,1) 49%,rgba(194,194,194,1) 93%,rgba(206,206,206,1) 94%,rgba(223,223,223,1) 95%,rgba(202,202,202,1) 96%,rgba(232,232,232,1) 97%,rgba(208,208,208,1) 98%,rgba(255,255,255,1) 100%); /* W3C */
/***** END INTIMIDATING PART ***************************************/
	border-radius: 10px;
	font-size: 120px;
	height: 150px;
	padding-top: 10px;
	text-shadow: #000 1px 1px 1px; /* Helps smooth the text */
	text-align: center;
	width: 150px;
	/* Add a box-shadow that is 50% transparent */
	-webkit-box-shadow: 0px 3px 10px rgba(0,0,0,0.5);
	-moz-box-shadow: 0px 3px 10px rgba(0,0,0,0.5);
	box-shadow: 0px 3px 10px rgba(0,0,0,0.5);
}
#hour {
	position: absolute; /* Position the minutes card in the top left */
		left: 36px;
		top: -15px;
}
#mins {
	position: absolute; /* Position the minutes card in the top right */
		right: 36px;
		top: -15px;
}

My solution to style the cards is to use one background gradient with several color stops to make lines that simulate multiple cards at the top and bottom and also give the appearance of a break in the middle. Color stops can be hard to get precise so once again I used the Ultimate CSS Gradient Generator, they have a feature where you can upload an image of a gradient and it will output the corresponding CSS for you. I uploaded an image of just the background of the card, including the lines at the top and bottom and it immediately gave me the perfect CSS I needed.

Lastly, we need to position the rest of the text for the location, weather, icon, and temps and do a little font styling.

#weather {
	color: #fff;
	text-shadow: 0 1px 2px rgba(0,0,0,0.75);  /* Give all text a slight shadow for readability */
}
#location {
	font-size: 16px;
	line-height: 22px;
	position: absolute;
		bottom: 15px;
		left: 15px;
}
#icon {
	position: absolute;
		bottom: -28px;
		left: 113px;
}
#temp {
	font-size: 34px;
	font-weight: normal;
	position: absolute;
		bottom: 12px;
		right: 60px;
}
#high-low-temps {
	position: absolute;
		bottom: 15px;
		right:  15px;
}

Javascript

To wrap this all up, let’s make the clock show the user’s actual time. We can do this with just a tiny bit of javascript that updates the time every second.

<script type="text/javascript">
var hour = document.getElementById('hour');
var mins = document.getElementById('mins');
function updateClock() {
  var d = new Date();
  var m = d.getMinutes();
  var h = d.getHours();
  hour.textContent = h;
  mins.textContent = m;
}
setInterval(updateClock, 1000);
</script>
Posted in

Seth Stevenson

Digital Marketing Expert For small businesses and non-profits Seth Stevenson is a Des Moines-based digital marketing expert. He provides a full range of marketing services, including web design, search engine optimization (SEO), online advertising, and more.