How to Build a Simple Advent Calendar in JavaScript

The 0.1 and 0.95 multipliers are in the equation to leave some space for the margins, between each doors, and around the sides of the Calendar, too.

The same way, the y property will be used by the top CSS positioning property, and likewise it determines in pixels where an individual Door needs to be placed on the y-axis.

Advent Calendars in a Supermarket

IMAGE: ChristmasCountDown.Co.Uk

For my demo Calendar I set a solid white border and white fonts for the enabled doors with a transparent white background on hovering; and a lightgreen border, and fonts, and a transparent lightgreen background for the disabled ones. If you don’t like this design you can change the colours and the styles according to your wish.

  • Demo
  • Download Source

JavaScript Calendar Design

If the Door is disabled, we add a class=”disabled” selector to the given anchor tag with the help of the className property. Remember, we’ve already styled the .disabled class with CSS in Step 4. We also need to set the onclick HTML event attribute to return false.

We create a doors[] array that will hold the 24 Door objects. We loop through the days from 1 to 24 (they will be the 0-23th elements of the doors[] array, as arrays are zero-based), and finally return the whole doors[] array including the 24 Door objects to display them in the browser.

Advent Calendar Screenshot

Step 1 – Create File Structure & Resources

 function Door(calendar, day) { this.width = ((calendar.width - 0.1 * calendar.width) / 4) * 0.95; this.height = ((calendar.height - 0.1 * calendar.height) / 6) * 0.95; this.adventMessage = 'Day ' + day + ' of Advent\n\n' + '"' + messages[day - 1][0] + '"\n\n\t' + 'by ' + messages[day - 1][1] + '\n\n'; this.x = ( 0.04 * calendar.width + ((day - 1) % 4) * (1.1 * this.width) ); this.y = - ( 0.96 * calendar.height - Math.floor((day - 1) / 4) * (1.1 * this.height) ); this.content = function() { ... }; }

Step 7 – Populate the “Content()” Method

It is the content() method that will display our doors in the browser. First of all, we create a new DOM node with the help of the variable node that will create the <li> elements inside our currently empty unordered list (ul#adventDoors) in the HTML file.

The innerHTML property in the next line displays the current day (1-24) on top of the door in the browser, and we also add a href=”#” attribute to our anchor tags by means of the href DOM property.

To make our Door object clickable we also need to add an <a> tag inside the list elements. We achieve this with the help of the innerNode variable that we bind as a child element to the appropriate list element identified by the id=”door[i]” selector (with the [i] being the day number), by using the appendChild() DOM method just like before.

Advent Calendar Background
 var myCal = document.getElementById("adventCal"); var currentDate = new Date();

Step 6 – Create the “Door” Class

As we need 24 doors, the most straightforward way to do this is to create a “Door” class, and later instantiate it 24 times.

We will make 5 properties and 1 method for the Door class. In this Step we will only go through the 5 properties, and I will explain the content() method in the next Step.

Based on local customs, Advent Calendars can have different designs, but most frequently they take the form of large rectangular cards with 24 windows or doors marking the days between Dec 1 and 24. The doors hide messages, poems, prayers or little surprises.

Advent Calendar File Structure

Step 2 – Create The HTML

The x property will be used by the left CSS positioning property in the next Step (Step 7). It determines in pixels where an individual Door needs to be placed on the x-axis.

In this post I will show you how to make an Advent Calendar in object-oriented JavaScript. As it’s made in vanilla JavaScript you can easily place the code into your own website.

The node.style.cssText property in the next line adds some CSS rules to each list element (door) with the help of the style=”…” HTML attribute that’s used to include inline CSS in HTML files. The node.style.cssText property uses the properties of the Door class that we set in the previous step (Step 6).

Then, with the help of the Math.floor() method we calculate in which row a given Door object will be (there will be 6 rows).

If the Door is in enabled state, we add the adventMessage property to an alert message, and place it inside the onclick HTML event attribute.

Our Advent Calendar will have 24 doors on a Christmas-themed background image. Each door will hide a Christmas-related quote that will pop up in the form of an alert message when the user clicks on the door. The doors remain closed until the given day comes, as it is the case with real life Advent Calendar; the doors cannot be opened before the right day.

This will be our only image resource for this project.

For Dec 1 the adventMessage property takes the first element of the outer array which is messages[0], as arrays are zero-based in JavaScript.

Finally we add a 10% margin for each Door object by multiplying its height using a 1.1 multiplier.

We take the height of the background image with the help of the height property of the passed in calendar parameter (that holds a DOM-object), and leave a 4% margin around the vertical sides of the Calendar.

When you are ready you have the resources and file structure you’ll need to accomplish this project, and your root folder looks something like this:

The HTML code we use is pretty straightforward. The CSS stylesheet is linked in the <head> section, while the two JavaScript files are included in the bottom of the <body> section. The latter is necessary, because if we put the scripts into the <head> section, the code wouldn’t be executed, as it uses the elements of the loaded HTML page.

For the same reason, the quote for Dec 1 is positioned as messages[0][0] (first element of the inner array), and the matching author can be reached as messages[0][1] (second element of the inner array).

Populate the array with your favourite quotes according to the following syntax:

Put the following code snippet into the top of your calendar.js file.

The currentDate variable holds the current date so that our script can easily decide if a door should be enabled or disabled. To create currentDate we instantiate a new object of the Date JavaScript class.

Below the image we place an empty unordered list with the “adventDoors” id selector that will be populated by the scripts. If the user doesn’t have JavaScript enabled in their browser, they will just see a simple Christmas image.

 this.content = function() { var node = document.createElement("li"); document.getElementById("adventDoors").appendChild(node); node.id = "door" + day; node.style.cssText = "width: " + this.width + "px; height: " + this.height + "px; top: " + this.y + "px; left: " + this.x + "px;"; var innerNode = document.createElement("a"); document.getElementById("door" + day).appendChild(innerNode); innerNode.innerHTML = day; innerNode.href = "#"; if( ( currentDate.getMonth() + 1 ) < 12 || currentDate.getDate() < day ) { innerNode.className = "disabled"; innerNode.onclick = function() { return false; } } else { var adventMessage = this.adventMessage; innerNode.onclick = function() { alert(adventMessage); return false; } } };

Step 8 – Initialize the “Door” Objects

Finally, we need to initialize the Door class 24 times.

It is fine if you prefer a landscape orientation. Just change the positions of the doors in the JavaScript code, as you’ll have 6 columns and 4 rows. If you have your image, create a folder called /images, and save it.

The “width” & “height” properties

After this, we check if the current date held in the currentDate global variable we set in Step 5 is less than the day that the current Door object represents.

 ul#adventDoors { position: relative; list-style: none; padding: 0; margin: 0; } #adventDoors li { position: absolute; } #adventDoors li a { color: #fff; width: 100%; height: 100%; font-size: 24px; text-align: center; display: flex; flex-direction: column; justify-content: center; text-decoration: none; border: 1px #fff solid; } #adventDoors li a:not(.disabled):hover { color: #fff; background-color: transparent; background-color: rgba(255,255,255,0.15); } #adventDoors li a.disabled { border-color: #b6fe98; background-color: rgba(196,254,171,0.15); color: #b6fe98; cursor: default; }

Step 5 – Create The Global Variables

From this step on, we will only work with the scripts/calendar.js file, so now let’s open this up. Our Advent Calendar will use two global variables.

The “adventMessage” property

The Advent Calendar itself is placed inside the <article> semantic tag. We load the Christmas image as an <img> HTML element, and not as a CSS background property, because this way we can easily access it as an element of the DOM.

It takes the width of the background image, and it leaves a little margin for it (4%). Then with the help of the remainder operator, it assesses in which column it will be placed (remember, there will be 4 columns), and finally it adds a little (10%) margin to each individual Door by using a 1.1 multiplier.

Properties x and y hold the proper positions of each door that we will use in the next step to set the top and left CSS properties. These will complement the position: relative and position: absolute CSS rules that we set in Step 4 for the door container (ul#adventDoors), and the doors themselves (#adventDoors li). The calculations may seem somewhat intimidating, but let’s go quickly through them.

The “x”&”y” properties

To do so, we use an Immediately Invoked Function Expression that is quite useful here, because we don’t need a variable as we only want to execute the code inside the function once.

Doors that are already enabled will have a different border and background colour (white) than the disabled ones (lightgreen). We will use HTML5, CSS3, and JavaScript to prepare our Advent Calendar that looks something like this:

The node.id property in the next line adds a unique id selector to each list element (door). We will need this to be able to properly loop through the days in the next step (Step 8). This way Door 1 will have an id=”door1″, Door 2 will have an id=”door2″ selector, etc.

The other important thing in the stylesheet file is to create a different design for the disabled and the enabled states. The .disabled selector will be added to the disabled by JavaScript.

Advent is the period of waiting and preparing for Christmas which begins four Sundays before Christmas eve. The passing of Advent time is traditionally measured with the help of either an Advent Calendar, or an Advent Wreath. Although the beginning of Advent is not a fixed date, Advent Calendars usually begin on Dec 1.

Place the following code (or your modified style rules) into your style.css file.

Finally, in the if-else statement, we evaluate if a Door object should be enabled or disabled. First, we examine if we are in the 12th month of the year (December) by using the getMonth() method of the Date object. We need to add 1, because getMonth() is zero-based (January is month 0, etc.).

The width and height properties dynamically calculate the width and height of each individual door (that changes according to the width and height of the background image).

If it’s not December, or the day represented by the given Door is bigger than the current date, the Door should be disabled, in any other cases it needs to be enabled so that users can click on it, and see the related Advent message.

The myCal variable holds the Calendar image as a JS object. The image has already been added to the index.html file in Step 2. We will place the doors onto this image in Step 7. We capture the related HTML <img> element marked with the “adventCal” identifier by using the getElementById() DOM method. The myCal variable will be an HTMLImageElement DOM object.

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Advent Calendar</title> <!-- Mobile-friendly viewport --> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Style sheet link --> <link href="style.css" rel="stylesheet" media="all"> </head> <body> <article> <h1>Advent Calendar</h1> <img src="advent-calendar-javascript/background.jpg" alt="Advent Calendar" id="adventCal"> <ul id="adventDoors"></ul> </article> <!-- Scripts --> <script src="scripts/messages.js"></script> <script src="scripts/calendar.js"></script> </body> </html>

Step 3 – Populate the “Messages” Array

We need 24 Christmas quotes to populate the “messages” array. I chose mine from GoodReads.

First of all, we need to choose a nice background image. I chose one with portrait orientation from Pixabay, so my calendar will contain 4 columns and 6 rows.

Open the scripts/messages.js file; we will place the quotes here to keep them separate from the functionality. The messages array is an array inside an array, each element of the outer array contains another array with two elements: a quote, and its author.

 var messages = [ ["Quote 1", "Author 1"], ["Quote 2", "Author 2"], ... ["Quote 24", "Author 24"] ];

Step 4 – Add Basic CSS Styles for the Doors

To create the necessary CSS styles for the doors we need to imagine the final design, as the doors themselves will be created with JavaScript in the following steps.

For the JavaScript files create a /scripts folder inside your root folder. Place two empty text files into it, and name them calendar.js and messages.js. Calendar.js will hold the functionality, while messages.js will contain the array of messages that pop up when the user “opens” (clicks on) the doors.

We need to create 4 columns and 6 rows of rectangles in proper alignment. For this, we will use the position: relative and the position: absolute CSS rules. As the exact position will change door by door, we will add the top, bottom, left, and right properties in the JavaScript, in the CSS we just need to add a relative position to the container (unordered list in the HTML), and absolute positions for the list elements (they will be added in the JS, too).

Our Door class has two parameters, calendar and day. For the calendar parameter we will need to pass the Christmas image that will function as the background. For the day parameter we will need to pass the current day of December in the form of an integer.

As the Door class will be instantiated 24 times in a for loop in the next Step (Step 8), this means that we will have 24 <li> elements, one li for each door. In the next line we append the new node to the #adventDoors unordered list as a child element by using the appendChild() DOM method.

We will pass the exact values of the parameters in the last step (Step 8), during the instantiation of the 24 Door objects.

The adventMessage property holds the content of the alert messages, namely the quotes and the matching authors that our messages.js file holds. The adventMessage property takes a quote and an author from the messages[] array, depending on the current date.

We will also need an HTML and a CSS file, so create two empty files inside your root folder and give them the names index.html and style.css.

 (function() { var doors = []; for(var i = 0; i < 24; i++) { doors[i] = new Door(myCal, i + 1); doors[i].content(); } return doors; })();
  • Demo
  • Download Source


Leave a Reply