Course: JavaScript

Progress (0%)

  1. Foundation

  2. Numbers

  3. Strings

  4. Conditions

  5. Loops

  6. Arrays

  7. Functions

  8. Objects

  9. Exceptions

  10. HTML DOM

  11. CSSOM

  12. Events

  13. Drag and Drop

  14. opt Touch Events

  15. Misc

  16. Project: Analog Clock

Project: Analog Clock

Project 1

Styling the clock

Although, it has been instructed in the description of this project that we shouldn't include anything inside .clock, we have to do so at least in these early stages of development. It's impossible to design a clock without thoroughly testing the design of each of its components.

We have to fill .clock with all of its components, style them, see how they look, and then once everything looks great, then consider about removing the components from the HTML, leaving this job to JavaScript.

So first thing's first, let's start with designing .clock.

Here's the CSS for .clock:

.clock {
   position: relative;
   display: inline-block;
   border: 6px solid lightgrey;
   background-color: #f8f8f8;
   padding: 80px;
   border-radius: 50%;
}

Let's understand the purpose of each style declaration here:

  • position: relative is applied so that later on we can absolutely position elements inside .clock.
  • display: inline-block is given only to enable the clock to be easily center-aligned on the HTML document (by applying text-align: center on the body element).
  • border: 6px solid lightgrey creates a nice thick frame around the clock.
  • background-color: #f8f8f8 is just a preferential style.
  • padding: 80px gives .clock a 160px of visual width and height. If you want to, you can increase or decrease this value depending on how large you want the clock to look. This is easier to set up than defining two separate statements, one for width: 160px and the other for height: 160px.
  • border-radius: 50% makes the clock round. Omitting this will give us a square-shaped clock which we don't find that interesting.

Altogether, this gives us the following:

Great!

Next up, let's get done with the graduations.

There are a total of 60 graduations on a clock, some of which are small while the others are large. Every 5th graduation in particular is large. Hence, we'd have the following HTML markup for the graduations:

<div class="clock">
   <div class="clock_graduation clock_graduation--large"></div>
   <div class="clock_graduation"></div>
   <div class="clock_graduation"></div>
   <div class="clock_graduation"></div>
   <div class="clock_graduation"></div>
   <!-- More graduations here... -->
   <div class="clock_graduation clock_graduation--large"></div>
   <div class="clock_graduation"></div>
   <div class="clock_graduation"></div>
   <div class="clock_graduation"></div>
   <div class="clock_graduation"></div>
</div>

But before this, we need to design .clock_graduation in such a way that it's easy for us to rotate it later on without much CSS. Likewise, let's first test our CSS with just one graduation — the smaller one:

<div class="clock">
   <div class="clock_graduation"></div>
</div>

The idea we use to style this element .clock_graduation is very simple.

Get the element to cover the entire area of .clock and then use the :before pseudo-element to act as the actual graduation, center-aligned horizontally and vertically-aligned to the top edge of the parent element.

The benefit of this approach is that we can easily rotate the graduation without having to configure transform-origin to an appropriate pivotal point.

Here's the CSS for .clock_graduation:

.clock_graduation {
   position: absolute;
   top: 0;
   bottom: 0;
   left: 0;
   right: 0;
}

.clock_graduation:before {
   content: '';
   position: absolute;
   top: 0;
   left: 50%;
   transform: translateX(-50%);
   width: 1px;
   height: 6px;
   background-color: grey;
}

First, let's understand the intuition behind the styles of .clock_graduation:

  • position: absolute freely positions .clock_graduation in .clock so that it's easy to move it via the properties top, right, bottom and left.
  • top: 0, bottom: 0, left: 0 and right: 0 all together make .clock_graduation fill the entire height and width of its container (i.e. .clock).
.clock_graduation won't be round in shape; it will be a square. The reason why we don't need to worry about rounding it is simply because it doesn't have any background color applied to it and likewise, we won't be able to notice this shape disparity between .clock and .clock_graduation.

So far, so good.

Now, let's come to .clock_graduation:before:

  • content: '' makes the :before element be rendered into view. As we know, without the content property applied to :before, the CSS engine doesn't consider its styles anyway.
  • position: absolute freely positions this pseudo-element in its parent (i.e. .clock_graduation) so that, later on, we can easily center-align it using the top and left properties.
  • top: 0 positions the top edge of this element to the top edge of its parent in order to start the graduation mark right from the clock's frame. If you want to, you can make the graduation a little bit further away from the edge of the clock's frame.
  • left: 50% and transform: translateX(-50%) together center-align this element horizontally in its parent.
  • width: 1px and height: 6px together give a dimension to the graduation mark.
  • background-color: grey applies a color to the mark.

Time to test it on our single element:

Notice the small vertical mark at the top of the clock's face. That's our minor graduation mark, represented as .clock_graduation.

Superb!

Now as instructed before, some graduations are large and represented via the class .clock_graduation--large. This is defined as follows:

.clock_graduation--large:before {
   height: 12px;
   width: 3px;
}

The large width and height declarations make .clock_graduation--large actually larger than just the .clock_graduation element.

Let's test this class as well:

And it looks great.

Now, it's time to test all these graduations in the clock at the same time, not just one single graduation. Obviously, for this we have to rotate each subsequent graduation by 6 degrees (360 / 60 = 6):

<div class="clock">
   <div class="clock_graduation clock_graduation--large" style="transform: rotate(0deg)"></div>
   <div class="clock_graduation" style="transform: rotate(6deg)"></div>
   <div class="clock_graduation" style="transform: rotate(12deg)"></div>
   <div class="clock_graduation" style="transform: rotate(18deg)"></div>
   <div class="clock_graduation" style="transform: rotate(24deg)"></div>
   <!-- More graduations here... -->
   <div class="clock_graduation clock_graduation--large" style="transform: rotate(330deg)"></div>
   <div class="clock_graduation" style="transform: rotate(336deg)"></div>
   <div class="clock_graduation" style="transform: rotate(342deg)"></div>
   <div class="clock_graduation" style="transform: rotate(348deg)"></div>
   <div class="clock_graduation" style="transform: rotate(354deg)"></div>
</div>

For now, we have to manually rotate each element in this testing phase. However, once we accomplish this in JavaScript, it'll automatically do this itself.

Here's the output of the HTML above:

Note that as per your preference, you can modulate the styles of these graduations as you like them to be for your clock.

Moving on, now it's time to consider the clock's hand.

.clock_hand represents a clock hand, which begins at the center of clock and is meant to rotate. In order to achieve this, we can once again go with the same old approach — get .clock_hand fill the entire area of .clock and then use its :before pseudo-element as the actual hand.

But before it, let's formulate its markup:

<div class="clock">
   <!-- More graduations here... -->
   <div class="clock_graduation" style="transform: rotate(354deg)"></div>

   <div class="clock_hand clock_hand--hours"></div>
   <div class="clock_hand clock_hand--minutes"></div>
   <div class="clock_hand clock_hand--seconds"></div>
</div>

With this markup in place, let's now consider the styles of each of these new elements, starting with .clock_hand:

.clock_graduation,
.clock_hand {
   position: absolute;
   top: 0;
   right: 0;
   bottom: 0;
   left: 0;
}

.clock_graduation:before { /* ... */ }

.clock_hand:before {
   content: '';
   position: absolute;
   left: 50%;
   transform: translateX(-50%);
   bottom: 50%;
}

.clock_hand is the same as .clock_graduation, hence we've reused the same ruleset for both of these elements.

Next, we have the definition of .clock_hand:before. It goes as follows:

  • content: '' makes this pseudo-element be rendered into view.
  • position: absolute allows it to move freely in its parent (i.e. .clock_hand).
  • left: 50% and transform: translateX(-50%), as before, together help center-align this element in its parent, horizontally.
  • bottom: 50% aligns the bottom edge of this element with the vertical mid-point of its parent. This makes the clock hand seem to originate from the center. If you want to, you can reduce this value in order to make the clock hand extend before the mid point.

Note that the ruleset of .clock_hand:before, as shown above, is incomplete for showcasing a given clock hand. And that's because the rest of the styles, which will be different for every hand, will be applied to the elements .clock_hand--hours, .clock_hand--minutes and .clock_hand--seconds separately.

Time to do that next:

.clock_hand:before { /* ... */ }

.clock_hand--hours:before {
   top: 25%;
   width: 3px;
   background-color: darkgrey;
}

.clock_hand--minutes:before {
   top: 15%;
   width: 3px;
   background-color: darkgrey;
}

.clock_hand--seconds:before {
   top: 5%;
   width: 1px;
   background-color: red;
}

Below is an explanation for the styles of .clock_hand--hours:

  • top: 25% positions the hours hand 25% from the top of the clock. (Recall that it is positioned by 50% from the bottom, hence, the height of the hours hand is 25% (100 - 50 - 25) of its parent.)
  • width: 3px sets the width of the hours hand. Typically, the hours and minutes hands on a clock are thicker than the seconds hand. Hence, the given styles.
  • background-color: darkgrey simply gives a color to the hours hand.

Similar reasoning can be applied for .clock_hand--minutes:before and .clock_hand--seconds:before. One important thing to note here is that, as per stated in the description of this project, the color of the seconds hand is red.

Let's now test these clock hands:

Wait a second... All the three clock hands overlap each other and consequently it's difficult to distinguish between them.

A simple way to solve this problem is to rotate the hours and minutes hand to some arbitrary angle. That's what we do below:

<div class="clock">
   <!-- More graduations here... -->
   <div class="clock_graduation" style="transform: rotate(354deg)"></div>

   <div class="clock_hand clock_hand--hours" style="transform: rotate(60deg)"></div>
   <div class="clock_hand clock_hand--minutes" style="transform: rotate(151deg)"></div>
   <div class="clock_hand clock_hand--seconds"></div>
</div>

And now it looks spectacular. What do you think?

The last thing left to be done is to add a hand nut at the center of the clock to hold all the three hands in place (obviously just for the sake of visual similarity with a real analog clock).

This is accomplished with the addition of a .clock_hand-nut element to our HTML:

<div class="clock">
   <!-- More graduations here... -->
   <div class="clock_graduation" style="transform: rotate(354deg)"></div>

   <div class="clock_hand clock_hand--hours"></div>
   <!-- More hands here... -->

   <div class="clock_hand-nut"></div>
</div>

The CSS is as follows:

.clock_hand-nut {
   position: absolute;
   padding: 6px;
   border-radius: 50%;
   transform: translate(-50%, -50%);
   top: 50%;
   left: 50%;
   z-index: 1;
   background-color: grey;
}

And here's the result:

Perfect!

With this, we have completely tested and perfected all the components of our clock. The next thing is to start thinking about its logic.