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>
  1. […] Recreating the HTC clock widget with CSS3 […]

  2. I have made a working version with weather, forecast, images, etc. However I have yet to get the flip animations to look good, or even work that well really. If anyone would like the source to see what you want to do with it please email me. It’s basically a few lines of php to lookup location, grab ip, and ask yahoo weather api for the forecast.

  3. […] Recreating the HTC clock widget with CSS3 | Seth Stevenson […]

  4. […] original del artículo: Seth Stevenson Blog Traducción realizada por […]

  5. Looks really neat – its just a shame that the css styling has to be so large (not a criticism of you!). I guess actually in this slightly contrived situation there isn’t really a reason not to just use a background image to provide design and simply overlay the text.

    This is going to be one of the major issues with css3 I think i.e. when and where to use css3 to supply the styling and when to just use a background image for simplicity. Ultimately, it will come down to time and money in the commercial sector and the level of uptake for CSS3 compatible browsers in your target market.

  6. Really amazing piece of work. The implementation of the “real” widget would just need a few lines of javascript to show the time and change the weather data and image accordingly.
    CSS really is only meant for the design not for the functionality! 🙂

    • Thanks. Yeah the time would be easy, weather would be a little more difficult. I’ve been trying to figure out a good way to do the “flip” animation though.

      • Seeing as we’re already showing off CSS3, I would try adding an extra layer for the current value (overlaying the new value behind it) and use a 3D transform to flip the current layer down. Then we can use Javascript to show and hide the correct layers.
        Alternatively, we could use jQuery to achieve the same effect.

  7. A bit too much CSS for my taste but a great job Seth. Nice example of of gradients for those who are just jumping on the practice.

  8. I too was expecting to see the real widget 🙂 but anyway you’ve done a work of art with CSS , totally remarkable good work and if time permits please create the real widget 🙂

  9. So you just recreated a screenshot of the clock in CSS? This is hardly a recreation of the HTC clock widget since it is completely static. Great example of what can be done with CSS gradients I guess…

    • Yes this is just a visual recreation. It was meant to show how CSS is evolving and can be used for more detailed styling. I hope to follow up at some point with the functionality behind this to make the clock and weather work.

      This method also has the benefit of being flexible in the sense that you can easily change the colors, sizes and details without generating a new image each time.

  10. […] Recreating the HTC clock widget with CSS3 […]

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Contact Me

How can I help you?

© 2022Seth Stevenson Marketing. All rights reserved.

Login to continue