Recreating the HTC clock widget with CSS3


One of the reason HTC’s phones are so popular right now is their slick interface. The most iconic part of their interface is their 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 in web design, it doesn’t work in IE, however all of the other major browsers work (Chrome, Firefox, Safari and Opera).

Here’s what we’ll be making:

HTC clock widget made with CSS3

View demo Download example

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 the lighter portion of the background.

CSS

First lets 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 {
	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 simulation 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;
}

View demo Download example


13 Comments

  1. Pingback:
  2. 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.


      Seth Stevenson -
  3. 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 :)


    Tharindu Abeydeera -
  4. 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.


  5. 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.


      Seth Stevenson -
      • 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.


  6. 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.


  7. Pingback:
  8. Pingback:
  9. 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.


  10. Pingback:

Speak up!