DEV Community

Divyamcm
Divyamcm

Posted on

Countdown Timer using HTML, CSS, and Javascript

===============================================

Dear Reader,

We might have come across e-commerce websites with countdown timers that give information on some sales or deals. We will create a web page where we will place a countdown timer that informs us about when the discount sale will end. Let’s implement one such scenario here. Countdown begins⏳ !!!

Folder Structure of the project:

  1. index.html — contains the HTML layout which defines the element structure that would be shown on the page.
  2. images are directly placed inside the folder of our project.
  3. style.css- contains CSS code for styling. Using CSS we can style the different portions to make them more visually appealing.
  4. script.js — contains Javascript code. There are several functions that work together to handle all the functions of the timer.

HTML Layout

Open VSCode and create the basic HTML structure in an index.html file by ! and then pressing tab. Give the title as ‘Countdown Timer*. Link **style.css* and script.js to the created HTML file.

Create a div class product that wraps around everything related to the product. I have used shoes as my discounted product for this example. Use img tag to add the image of the shoe.

Add the following div class,

details — to hold information on the deal.

wrap — which wraps timer and text.

timer — to hold the entire countdown timer.

days, hours, mins, and secs — to hold the remaining days, hours, mins, and secs.

Let days, hours, mins, and secs class contain span tag with id days_left, hours_left, mins_left, and secs_left respectively. The dynamic data will go inside the span element and id will be used in javascript code to fetch the element.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Countdown Timer</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <h1> Best deals of the day</h1>
    <div class="product">
        <img src="shoe.jpg" alt="shoes" width="400px" height="300px">
        <div class="details">
            <h3>🔥30% off on all branded shoes🔥</h3>
            <p> This festive season we have multiple amazing offers on all branded shoes.
                Bank and payment offers, and many more deals.This sale brings hundreds of deals
                across all branded shoes. To help you find the best discounts,
                we've handpicked some of the best deals and offers available on shoes during the ongoing discount Sale. Grab the offer soon!!🤩
            </p>
            <div class="wrap">
                <h3 class="offer">Offer ends in</h3>
                <div class="timer">
                    <div class="days">
                        <span id="days_left"> 0</span>
                        days
                    </div>
                    <div class="hours">
                        <span id="hours_left"> 0 </span>
                        hours
                    </div>
                    <div class="mins">
                        <span id="mins_left"> 0 </span>
                        mins
                    </div>
                    <div class="secs">
                        <span id="secs_left"> 0 </span>
                        secs
                    </div>
                </div>
            </div>
        </div>
    </div>
    <script src="style.js"></script>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode

CSS Styling

Quite a bit of CSS coding is required to make the page visually appealing and even without much CSS, we can implement the basic countdown timer.

Below is the code,


@import url('https://fonts.googleapis.com/css2?family=Oswald&display=swap');

body{
    font-family: 'Oswald', sans-serif;
    align-content: center;
    text-align: center;
    background-color:rgb(244, 248, 250);
}

.product{
display: flex;
background-color: rgb(237, 243, 243);
gap: 7rem;
}

.details{
    display:flex;
    flex-direction: column;
    margin-right: 150px;  
}

.wrap{
    display: flex;
    flex-direction: row;
}
.timer{
    display: flex;
    text-align: center;
    flex-direction: row;
    margin-left: 3rem;
    gap: 30px;
    color:red;
    margin-top: -5px;

}
.days{
    background-color: blanchedalmond;
    padding: 11px;
    font-size: 22px;
}


.hours{
    background-color: blanchedalmond;
    padding: 11px;
    font-size: 22px;
}
.mins{
    background-color: blanchedalmond;
    padding: 11px;
    font-size: 22px;
}

.secs{
    background-color: blanchedalmond;
    padding: 11px;
    font-size: 22px;
}


h3{
    color:lightseagreen;
}

.offer{
    flex-basis: 6rem;
}

p{
    text-align: left;
}


Enter fullscreen mode Exit fullscreen mode

Javascript logic

The whole idea is to calculate the time left before the offer ends. To calculate the time left we will take the difference of the current date and offer end date and present it in valid format.

Let’s create a function called countdown() in which we will declare a const called today and offerDate to add the current date and offer end date objects respectively.

const today = new Date();  
var offerDate = new Date('30 oct 2021');
Enter fullscreen mode Exit fullscreen mode

Assign the difference between offerDate and today to the const offerTime which will give the time left in milliseconds.

const offerTime = offerDate - today;
Enter fullscreen mode Exit fullscreen mode

Let’s calculate the number of days, hours, mins, and secs left using the offerTime value.

To calculate seconds:

  1. Divide milliseconds by 1000 to convert to seconds: (offerTime/1000)
  2. Divide the total seconds by 60 and grab the remainder. You don’t want all of the seconds, just those remaining after the minutes have been counted: (offerTime/1000) % 60
  3. Round this down to the nearest whole number. This is because you want complete seconds, not fractions of seconds: Math.floor( (offerTime/1000) % 60 )

To calculate minutes:

  1. Divide milliseconds by 1000 to convert to seconds: (offerTime/1000)
  2. Divide the total seconds by 60 to get the minutes( 1 min = 60 secs), again divide by 60 and grab the remainder. Round this down to the nearest whole number. Math.floor((offerTime / (1000 * 60) % 60))

To calculate hours:

  1. Divide milliseconds by 1000 to convert to seconds: (offerTime/1000)
  2. Divide the total seconds by 60 to get the minutes( 1 min = 60 secs),again divide by 60 (1 hour = 60 minutes), divide the result by 24 (1 day = 24 hours)and grab the remainder. Round this down to the nearest whole number. Math.floor((offerTime / (1000 * 60 * 60) % 24))

To calculate days:

  1. Divide milliseconds by 1000 to convert to seconds: (offerTime/1000)
  2. Divide the total seconds by 60 to get the minutes( 1 min = 60 secs),again divide by 60 (1 hour = 60 minutes), divide the result by 24 (1 day = 24 hours). Round this down to the nearest whole number. Math.floor((offerTime / (1000 * 60 * 60 * 24))

Once we have all the values we will set days, hours, mins, and secs to HTML span element.HTML element where the value to be set is fetched using getElementById() method and using innerHTML set the calculated values.

const days\_el = document.getElementById("days\_left");  
days\_el.innerHTML = offerDays;const hours\_el = document.getElementById("hours\_left");  
hours\_el.innerHTML = offerHours;const mins\_el = document.getElementById("mins\_left");  
mins\_el.innerHTML = offerMins;const secs\_el=document.getElementById("secs\_left");  
secs\_el.innerHTML = offerSecs;
Enter fullscreen mode Exit fullscreen mode

I added one more function just to reset the offer date once the offer date reaches the current date. We can ignore this function if not required.

Using setInterval() method call the countdown() function every second.

setInterval(countdown, 1000);

function countdown() {
    const today = new Date();
    var offerDate = new Date('30 oct 2021');

    //If offer ends reset to new value
    if (today.getSeconds() == offerDate.getSeconds()) {
        offerDate = resetOfferDate();
    }

    //offerTime will have the total millseconds 
    const offerTime = offerDate - today;

    // 1 sec= 1000 ms
    // 1 min = 60 sec
    // 1 hour = 60 mins
    // 1 day = 24 hours
    const offerDays = Math.floor(offerTime / (1000 * 60 * 60 * 24));
    const offerHours = Math.floor((offerTime / (1000 * 60 * 60) % 24));
    const offerMins = Math.floor((offerTime / (1000 * 60) % 60));
    const offerSecs = Math.floor((offerTime / 1000) % 60);

    const days_el = document.getElementById("days_left");
    days_el.innerHTML = offerDays;
    const hours_el = document.getElementById("hours_left");
    hours_el.innerHTML = offerHours;
    const mins_el = document.getElementById("mins_left");
    mins_el.innerHTML = offerMins;
    const secs_el = document.getElementById("secs_left");
    secs_el.innerHTML = offerSecs;
}

function resetOfferDate() {
    const futureDate = new Date();
    futureDate.setDate(futureDate.getDate() + 15);
    return futureDate;
}

setInterval(countdown, 1000);
Enter fullscreen mode Exit fullscreen mode

We’ve finished coding! Time to check the output.

All of the above-written code is available on GitHub. Watch this space for more interesting articles, up next in this series!

Thanks for your interest.

Discussion (11)

Collapse
lukeshiru profile image
LUKESHIRU • Edited on

Ideally we should keep the logic for the difference between the dates and the logic to show that separated, to make it more reusable. So you could have something like this:

/** @param {number|string|Date} [date2] */
export const dateDiff =
    (date2 = new Date()) =>
    /** @param {number|string|Date} [date1] */
    (date1 = new Date()) =>
        (diff => ({
            years: diff.getUTCFullYear(),
            months: diff.getUTCMonth(),
            days: diff.getUTCDate() - 1,
            hours: diff.getUTCHours(),
            minutes: diff.getUTCMinutes(),
            seconds: diff.getUTCSeconds(),
            milliseconds: diff.getUTCMilliseconds()
        }))(
            new Date(
                Math.abs(
                    new Date(date2).getTime() - new Date(date1).getTime()
                ) - 621672192e5
            )
        );
Enter fullscreen mode Exit fullscreen mode

That function then can be used from anywhere to get the absolute difference between two dates, so then you can do something like this (I used textContent instead of innerHTML which is safer):

import { dateDiff } from "./dateDiff.js";

const diffWithOffer = dateDiff("30 oct 2021");

setInterval(() => {
    const { days, hours, minutes, seconds } = diffWithOffer();

    document.querySelector("#days_left").textContent = days;
    document.querySelector("#hours_left").textContent = hours;
    document.querySelector("#mins_left").textContent = minutes;
    document.querySelector("#secs_left").textContent = seconds;
}, 1e3);
Enter fullscreen mode Exit fullscreen mode

Cheers!

Collapse
supportic profile image
Supportic

I think you forgot to put in new Date() into diffWithOffer closure function.
diffWithOffer(new Date())

Collapse
lukeshiru profile image
LUKESHIRU

It was intentional. When you do new Date(undefined) it gives you the current date, so if you call the curried function without arguments, is calculates based on the current date ☺️

Thread Thread
supportic profile image
Supportic

When I called the function without parameters date1 was undefined and it returned undefined o.o

Thread Thread
lukeshiru profile image
LUKESHIRU • Edited on

You're right, wth?! JavaScript being JavaScript I guess ... if you do new Date() it gives you the current date, but if you do new Date(undefined) which should be the same, it returns an Invalid Date .... gosh ... I'll update the original code! ... thanks for debugging it!

Thread Thread
supportic profile image
Supportic • Edited on

No worries new Date(undefined) always throws 'Invalid Date' in the console and new Date(null) returns the starting point.
Thanks for the neat snippet though.
Could you also explain why we subtract 621672192e5 ?

Thread Thread
lukeshiru profile image
LUKESHIRU

Sure, that 621672192e5 value is 0000-01-01T00:00:00.000Z, so the "first day" of the Gregorian calendar, if we have two dates and we subtract that, we get the "difference" between those two dates ... this is still the "cheap/non-exact" version, if you want something more useful, you might have to update it so it does the actual values for each property. I might do that later so the example is more useful for other folks.

Collapse
exenestecnico profile image
Ernesto

Recently made a Launch countdown project from fontendmentor.io. It has a flip animation for the number cards, and I learned about web components. The source code is there if someone wants to look at it.

Collapse
sadanandpai profile image
Sadanand Akshay Pai • Edited on

Nice timer.
Please host the pages on github pages. will be easy for others to view.
Here is mine: github.com/sadanandpai/frontend-mi...

Collapse
shikkaba profile image
shikkaba

Sooooo if I wanted just a countdown timer like 10 minutes from now instead of a specific date, how would I achieve that?

Collapse
divyamcm profile image
Divyamcm Author • Edited on

var offerDate = new Date('30 oct 2021')
Instead of the above format, you can use below format
new Date(year, month, day, hours, minutes, seconds, milliseconds) .
Ex: var offerDate = new Date(2021,09,16,09,20,0,0)

Set the values ten minutes ahead of current time to acheive 10 minutes countdown timer.