How to build a stopwatch with HTML, CSS, and plain JavaScript (Part 1)
Tags: tutorial, html, css
Published: 2020-07-09 17:26:28

---
series: How to build a stopwatch with HTML, CSS, and plain JavaScript
canonical_url: https://tinloof.com/blog/how-to-build-a-stopwatch-with-html-css-js-react-part-1/
---
<figure>
  <img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1591011589/blog/time-in-js/Functional.gif" alt="Stopwatch built with HTML, CSS, and JS" />
  <figcaption>Build your own stopwatch with HTML, CSS, and JavaScript</figcaption>
</figure>

This series of articles is made out of two parts:

In this first part, we build the stopwatch's user interface with HTML and CSS.

[In the second part](https://tinloof.com/blog/how-to-build-a-stopwatch-with-html-css-js-react-part-2/), we'll make the user interface functional with JavaScript (the stopwatch works).

### Final result

This is what we will build:

Here's the [link to the GitHub repo](https://github.com/tinloof/gold-stopwatch).

Here's the link to the [stopwatch itself.](https://gold-stopwatch.netlify.app/)

# 1- Folder structure and set-up

Our folder contains an HTML file, a CSS file, a JavaScript file,  and a folder (called "icons") with 3 SVG icons:

```markdown
├── icons
|  ├── pause-button.svg
|  ├── play-button.svg
|  └── reset-button.svg
├── index.html
├── script.js
└── style.css
```

Here is a [link to iconify](https://iconify.design/) to download the SVG icons.

### HTML DOCTYPE declaration

In the *index.html* file, we include the HTML DOCTYPE declaration at the top of the page to inform the browser that the document being rendered is an HTML document: 

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>
```

> 💡 **Tip**: you can easily generate the DOCTYPE declaration on VSCode by typing "!" and hitting ENTER in an HTML file.

### Link HTML file with CSS file

Next, we link our HTML file with our CSS file by adding the following to our `head`:

```html
<link rel="stylesheet" href="style.css" />
```

> 💡 **Tip**: you can easily generate the link on VSCode by typing `link:css` .

We get:

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css" />
</head>
<body>
    
</body>
</html>
```

### Link HTML file with JS file

Lastly, we connect our HTML file with our JS file by adding the following `script` before our `body` closing tag:

```html
<script src="script.js"></script>
```

We get:

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css" />
</head>
<body>
    <script src="script.js"></script>
</body>
</html>
```

Great, we are now ready to code the stopwatch.

> **Note:** the script.js file will be empty in this article since we only will implement the functionality in the next part of this series.

# 2- Create the HTML markup

First, we change the content wrapped by the `title` tags so the browser's tab's name is more relevant. 

We write "Gold Stopwatch" instead of "Document":

<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1591012447/blog/time-in-js/Change%20HTML%20title.gif" alt="Change the title of the document"/>
<figcaption>Change the title of the page</figcaption> 
</figure>

In the `body`, add an `h1` that says "GOLD STOPWATCH" and add a `span` that says "00:00:00". 

This is the code:

```html
<body>    
    <h1>GOLD STOPWATCH</h1>
    <span>00:00:00</span>
    <script src="script.js"></script>
</body>
```

We get:

<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1590928474/blog/time-in-js/H1%20and%20div.png" alt="H1 and span tags only" />
<figcaption>Only h1 and span</figcaption> 
</figure>


Next, we add buttons so we later can click on those and have a functional stopwatch. Our buttons have SVG images stored in our icons folder.

Add `button` s this way:

```html
<body>
  <h1>GOLD STOPWATCH</h1>
  <span>00:00:00</span>

  <button>
    <img src="icons/play-button.svg" />

    <img src="icons/pause-button.svg" />
  </button>

  <button>
    <img src="icons/reset-button.svg" />
  </button>
	<script src="script.js"></script>
</body>
```

On purpose, we include two icons in the first button (both the Play and Pause icons) because we will configure this button to serve both the Play and Pause functions later in the JavaScript part. 

When we'll click on the Play icon, it will disappear and the Pause icon will appear instead. Vice-versa, when we click on the Pause icon, it will disappear and the Play icon will appear instead.

This is what we get:
<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1593353696/blog/time-in-js/Screenshot_2020-06-28_at_16.14.13_aljy4w.png" alt= "HTML skeleton of the page"/>
<figcaption>The page structure is complete</figcaption> 
</figure>

Voilà! We are done with most of the HTML. We are now going to style it with CSS.

# 3- Style the HTML with CSS

### Add Google Fonts

We want to use the *Montserrat* font for most of the text on the web page. For the numbers in the stopwatch, we want to use *Roboto Mono*.

To add these fonts, we search for them on [Google Fonts](https://fonts.google.com/) and repeat the following steps for each one of them:

1- Click on *+* *Select this style.*

2- A window containing the font's `link` tag will pop up on the right. We copy the `link` tag and paste it in the `head` of the HTML document. 

This is how it looks like:
<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1591124594/blog/time-in-js/Google_fonts_wu4msp.png" alt="Adding fonts from Google Fonts"/>
<figcaption>Add fonts from Google Fonts</figcaption> 
</figure>

This is the result:

```html
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Gold Stopwatch</title>
    <link rel="stylesheet" href="style.css" />
    <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@200;900&display=swap"
    rel="stylesheet"/>
    <link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,300;1,300&display=swap"
    rel="stylesheet"/>
</head>
```

### Setting the first colors

Let's start by setting our page text and background colors. Our page text will be in white and background color in dark blue.

We target the `body` selector in `style.css`:

```css
body {
  background-color: #31394c;
  color: #ffffff;
}
```

This is what we get:

<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1591979024/blog/time-in-js/page%20text%20and%20background%20color%20set.png" alt="Changing the backaground color and color of the page"/>
<figcaption>background-color and color styled</figcaption> 
</figure>

### Style the `h1`

Next, we want to give more importance to "GOLD STOPWATCH". Let's style it:

```css
h1 {
    font-size: 48px;
    font-family: "Montserrat", sans-serif;
    font-weight: 200;
    
    text-align: center;
    line-height: 59px;
    
    padding: 0;
    margin: 0;
  }
```

> **Note:** the `h1` tag has some built-in margins in the browsers. We override them using `margin: 0`.

We get:

<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1591979287/blog/time-in-js/Styled%20H1.png" alt="Center the H1 tag" />
<figcaption>Centered h1</figcaption> 
</figure>

### Style one single world in the `h1`

If we recall, our `h1` is not uniform, "GOLD" appears in yellow with a *glow* effect while "STOPWATCH" appears in white. 

To achieve that, we wrap GOLD around a `span` and give it a `class` that we name *gold:*

```html
  <h1>
    <span class="gold">GOLD</span> STOPWATCH
  </h1>

  <span>00:00:00</span>
```

Now let's style this new `class:`

```css
.gold {
    font-weight: 900;
    
    color: #f2c94c;
    text-shadow: 0 0 0px #fff, 0 0 50px #f2c94c;
  }
```

We get:
<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1591979514/blog/time-in-js/Styled%20GOLD%20word.png" alt="Styling one word"/>
<figcaption>Styling "GOLD"</figcaption> 
</figure>

We use `text-shadow` to create a glow effect.  To understand how it works, [here's](https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow) a w3schools explanation on how to achieve that. 

### Style the position of elements

If we look at our final result, we can think of the stopwatch app as a column of three blocks:

<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1591980214/blog/time-in-js/Final%20result%20blocks.png" />
</figure>

If we inspect the final result, we can see three blocks:

- The `h1`  block
- The time `span` block
- The buttons block (which we will wrap in a `div`)

The blocks are separated by a gap of `23px`  and centred horizontally in the page.

To center the elements horizontally, the column should occupy the whole page width.

We create this column `div` and give name its `class`  *stopwatch*, and wrap our buttons with a `div`:

```html
<div class="stopwatch">
  <h1>
    <span class="gold">GOLD</span> STOPWATCH
  </h1>
  <span>
    00:00:00
  </span>

  <div>
    <button>
      <img src="icons/play-button.svg" />

      <img src="icons/pause-button.svg" />
    </button>

    <button>
      <img src="icons/reset-button.svg" />
    </button>
  </div>
</div>
```

Let's style it as a column:

```css
.stopwatch {
    display: grid;
    justify-items: center;
    grid-row-gap: 23px;
    width: 100%;
    padding-top: 25px;
  }
```

Our *stopwatch* `class` is a `grid` that stretches the whole page (`width` of 100%) and separates its blocks with 23px with `grid-row-gap`.

We also added `25px` padding on the top to have some space above the title.

<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1591980772/blog/time-in-js/Centered%20column.png" alt="Using CSS grids for a structured layout" />
<figcaption>Separating the stopwatch app in three blocks</figcaption> 
</figure>

We add a `class` to the span containing "00:00:00" and name it *time*:

```html
<div class="stopwatch">
  <h1>
    <span class="gold">GOLD</span> STOPWATCH
  </h1>

  <span class="time">00:00:00</span>
</div>
```

Now let's style "00:00:00" to make it larger and with the right font:

```css
.time {
  font-family: "Roboto Mono", monospace;
  font-weight: 300;
  font-size: 48px;
}
```

Here's the result:

<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1591981284/blog/time-in-js/Screenshot_2020-06-12_at_19.00.58_rse0im.png" alt="Styling the span that wraps time" />
<figcpation>Style the time `span`</figcaption> 
</figure>

### Create a circle with CSS

To get a circle around "00:00:00", we wrap it around another `div` that we call *circle:*

```html
<div class="stopwatch">
  <h1>
    <span class="gold">GOLD</span> STOPWATCH
  </h1>
  <div class="circle">
    <span class="time">00:00:00</span>
  </div>
</div>
```

To make a div look like a circle, we give it `border` and add a 50% `border-radius`. 

We get:

<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1591981963/blog/time-in-js/Screenshot_2020-06-12_at_19.12.32_avelzf.png" alt="Use border and border-radius to create a circle"/>
<figcaption>We use border and border-radius to create a circle</figcaption> 
</figure>

To make it look like a circle, we give it exact proportions. We will set both the `height` and `width` to 270px:

<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1591982040/blog/time-in-js/Screenshot_2020-06-12_at_19.13.48_pov0qk.png" alt="Give the exact width and height to the circle"/>
<figcaption>Give the circle the exact width and height</figcaption> 
</figure>

To center the time inside it both horizontally and vertically, we use [Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/). 

We give a `display` of `flex` to the *circle* `div`. 

To center the time vertically, we use `align-items: center`:
<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1591982187/blog/time-in-js/Screenshot_2020-06-12_at_19.16.16_xvim0w.png"/>
</figure>

And to center the time `span` horizontally, we use `justify-content: center`:
<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1591981491/blog/time-in-js/Screenshot_2020-06-12_at_19.04.39_rapir0.png"/>
</figure>
Here is the code:

```css
 .circle {
    display: flex;
    justify-content: center;
    align-items: center;
    
    height: 270px;
    width: 270px;
    
    border: 2px solid white;
    border-radius: 50%;
  }
```

If you need a refreshment on what flexbox and CSS grid are, this great YouTube channel [Layout Land](https://www.youtube.com/channel/UC7TizprGknbDalbHplROtag/videos) by [Jen Simmons](https://twitter.com/jensimmons?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor) will help.

If instead of `border-radius` 50% we make it 0%, we would get a square instead of a circle:
<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1591981760/blog/time-in-js/Square%20time.png" alt="Create a square border with CSS"/>
<figcaption>Square border</figcaption>  
</figure>

### Style the `button`s

Let's now focus on styling the `button`s:

```css
button {
    background: transparent;
    padding: 0;
    border: none;
    margin: 0;
    outline: none;
}
```

We get:
<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1591018809/blog/time-in-js/Buttons%20cleaned.png" />
</figure>

Now let's place them in the center by targeting the `div` *controls* we just created:

We want our Pause icon to overlap with the Play icon, and create a space between the Pause/Play `button` and the Reset `button`. We wrap our buttons around a `div` we call *controls*:

```html
<body>
  <div class="stopwatch">
    <h1>
      <span class="gold">GOLD</span> STOPWATCH
    </h1>
    <div class="circle">
      <span class="time" id="display">
        00:00:00
      </span>
    </div>

    <div class="controls">
      <button class="buttonPlay">
        <img src="icons/play-button.svg" />

        <img src="icons/pause-button.svg" />
      </button>

      <button class="buttonReset">
        <img src="icons/reset-button.svg" />
      </button>
    </div>
  </div>
  <script src="script.js"></script>
</body>
```

This new `div` *controls* will be given a `display` `flex` , give it a fixed `width` and use `justify-content: space-between` to properly distribute the space:

```css
.controls {
    display: flex;
    justify-content: space-between;
    
    width: 187px;
  }
```

We get:
<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1590942655/blog/time-in-js/Spaced%20Buttons.png" alt="Spacing two buttons with CSS"/>
<figcaption>We create a space between our first and second button</figcaption> 
</figure>

Recall both the Play and Button SVGs are in the same `button`. For now, we only want to show the Play button and hide the Pause button. 

Let's give `id`s to those SVGs (and to the Reset Button too, since we'll use it later):

```html
<body>
  <div class="stopwatch">
    <h1>
      <span class="gold">GOLD</span> STOPWATCH
    </h1>
    <div class="circle">
      <span class="time" id="display">
        00:00:00
      </span>
    </div>

    <div class="controls">
      <button class="buttonPlay">
        <img id="playButton" src="icons/play-button.svg" />

        <img id="pauseButton" src="icons/pause-button.svg" />
      </button>

      <button class="buttonReset">
        <img id="resetButton" src="icons/reset-button.svg" />
      </button>
    </div>
  </div>
  <script src="script.js"></script>
</body>
```

And use the `display` property to show the Play icon and hide the Pause icon:

```css
#playButton {
  display: block;
}

#pauseButton {
  display: none;
}
```

We get:
<figure>

<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1590943054/blog/time-in-js/Organized%20Buttons.png" alt="Hide buttons with CSS"/>

<figcaption>We successfully hide the Pause button</figcaption> 
</figure>

> **Note:** we could use `class`es for playButton and pauseButton, but we use `id`s because it will be helpful in the second part of this series.

### Style the `cursor`

Let's make our buttons have a hand/pointer `cursor`:

```css
button {
  cursor: pointer;
  background: transparent;
  padding: 0;
  border: none;
  margin: 0;
  outline: none;
}
```

Here is the result:
<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1590944099/blog/time-in-js/GIF%20Cursor%20Pointer.gif"/>
</figure>

# (Bonus) Add a favicon

As a final touch, let's add a favicon, so our page has a proper tab icon in the browser:

<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1590943597/blog/time-in-js/Favicon.png" />
</figure>

We can do this by adding a link tag to the HTML `head` that points to our icon svg:

```html
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⏳</text></svg>">
```

The `head`  looks like this now:

```html
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Gold Stopwatch</title>
    <link rel="stylesheet" href="style.css" />
    <link
      href="https://fonts.googleapis.com/css2?family=Montserrat:wght@200;900&display=swap"
      rel="stylesheet"/>
    <link
      href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,300;1,300&display=swap"
      rel="stylesheet"/>
    <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⏳</text></svg>">
  </head>
```

# Test responsiveness

Our stopwatch is also responsive. This is because we relied on CSS layouts like `grid` and `flexbox` to style the positioning of our elements.

Let's test it.

If we are on Chrome, we open the console (⌘+SHIFT+C for Mac or Ctrl+SHIFT+J on Windows) and select iPhone 5 SE (which is a small display size):

<figure>
<img loading="lazy" src="https://res.cloudinary.com/https-tinloof-com/image/upload/v1590946075/blog/time-in-js/responsive-iphone_gd6vdq.gif" />
</figure>

Great, it works.

# Functionality (JavaScript)

[In the next part of this series](https://tinloof.com/blog/how-to-build-a-stopwatch-with-html-css-js-react-part-II/), we'll focus on the functionality of the stopwatch with JavaScript.