Memory Game consists of boxes or cards that we have to match to play the game. It requires CSS animations and JavaScript to build it, especially to reveal the boxes and match the cards. This is the demo of the game we’re going to build and this is the GitHub Repo.
These are the steps to make the memory game :
- Build the UI
- Randomize the box orders
- Match the boxes
1. Build the UI
First of all, we got to set up our files. We’ll need index.html, style.css and script.js.
In the index.html, we’ll layout the basic HTML structure with links to style.css and script.js as well a main tag with 9 div with box class in it. That’ll our board and boxes for the game. To make the game simple and focusing more on the JS, we’ll use numbers instead of images. You’ll notice that the boxes are in order (1, 1, 2, 2 until 6), don’t worry about that, we’ll randomize their order in the next step with JavaScript.
<!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">
<link rel="stylesheet" href="./style.css">
<title>Memory Game</title>
</head>
<body>
<main>
<div class="box">1</div>
<div class="box">1</div>
<div class="box">2</div>
<div class="box">2</div>
<div class="box">3</div>
<div class="box">3</div>
<div class="box">4</div>
<div class="box">4</div>
<div class="box">5</div>
<div class="box">5</div>
<div class="box">6</div>
<div class="box">6</div>
</main>
<script src="./script.js"></script>
</body>
</html>
Your page should look like the image below now. Well, it’s nothing much yet. That’s why we’ll get into the CSS next to style it.
These below are the CSS we need to make our game look like the demo.
* {
box-sizing: border-box;
}
body {
margin: 0;
display: flex;
align-items: center;
justify-content: center;
width: 100vw;
height: 100vh;
}
main {
display: flex;
flex-wrap: wrap;
width: 600px;
}
.box {
width: 150px;
height: 150px;
background-color: darkblue;
color: transparent;
display: flex;
font-size: xx-large;
font-weight: bold;
align-items: center;
justify-content: center;
border: 1px solid black;
cursor: pointer;
}
And these are the CSS for the animations. We need it to show / reveal and hide our boxes.
@keyframes show {
0% {
background-color: darkblue;
color: transparent;
}
100% {
background-color: white;
color: black;
}
}
.hide {
animation: hide 2s forwards;
}
@keyframes hide {
0% {
background-color: white;
color: black;
}
100% {
background-color: darkblue;
color: transparent;
}
}
2. Randomize the box orders
Currently our game boxes are in order and that’s not fun to play. So, we’re gonna randomize the order using JavaScript. First, we get all the boxes and we loop through them. We’ll generate random numbers using math functions and assign them to the order attributes of the boxes. (flexbox has order attribute to determine which box to display first). You don’t have to worry about the numbers overlapping since CSS will solve it so they don’t overlap.
const boxes = document.querySelectorAll('.box');
boxes.forEach(function(box) {
let randomNum = Math.floor(Math.random() * 12);
box.style.order = randomNum;
});
Now your boxes should be randomized.
3. Match the boxes
This below is the JavaScript code we need to match the boxes. It’s a bit long but I’ll break it down in a second.
let first;
let second;
let matchCounter = 0;
boxes.forEach(function(box) {
box.addEventListener('click', function() {
if (!first && !second) {
first = box;
box.classList.add('show');
} else if (first && !second) {
second = box;
box.classList.add('show');
if (first.innerHTML === second.innerHTML) {
first.style.pointerEvents = 'none';
second.style.pointerEvents = 'none';
first = null;
second = null;
matchCounter++;
if (matchCounter >= 6) setTimeout(() => alert('Game done! Refresh page to replay.'), 2000 );
} else {
first.classList.add('hide');
second.classList.add('hide');
setTimeout(() => {
first.classList.remove('show');
second.classList.remove('show');
first.classList.remove('hide');
second.classList.remove('hide');
first = null;
second = null;
}, 2000);
}
}
})
});
Let’s break it down. First, this code below initializes the global variables. We are pairing the cards, so first means the first card and second means the second card to be paired. Then the matchCounter is used to count the number of pairs so far to determine whether the game is done or not.
let first;
let second;
let matchCounter = 0;
Then, we loop through the boxes and add a click listener to each of the that will invoke a function for the game.
boxes.forEach(function(box) {
box.addEventListener('click', function() {
// the remaining code will be here...
})
});
Inside the listener, you’ll se a huge block of if else. I’ll explain it to you. First, this block below means that you are still opening your first box, so we’ll only assign that box to the first variable and give it a show class to reveal the content of the box. The else if means it’s the second card turn. Here we’ll do the same thing as the first if block and we’ll also put the matching logic.
if (!first && !second) {
first = box;
box.classList.add('show');
} else if (first && !second) {
second = box;
box.classList.add('show');
// more if else..
}
Inside the else, there’s another if block inside, I’ll explain the if, then after that, the else.
The first if is for if the boxes match. If the match, we’ll make them not clickable to avoid it being chosen again. Then because it means 2 boxes have been picked, we’ll reset the first and second variable to null to allow new cards to be picked, Then we’ll add matchCounter to determine the number of matches if if there are 6 matches, we’ll alert the user indicating the game is done in a 2 second delay (because we want to wait until the show animation is done which is 2 seconds).
if (first.innerHTML === second.innerHTML) {
first.style.pointerEvents = 'none';
second.style.pointerEvents = 'none';
first = null;
second = null;
matchCounter++;
if (matchCounter >= 6) setTimeout(() => alert('Game done! Refresh page to replay.'), 2000 );
}
As for the else, it is used when the boxes are not a match. Because they’re not a match, we want to close them again by adding the hide class. Then, in a 2 second delay (waiting for the animation is done), we remove the show and hide classes enabling them to be able to be clicked again (if the classes remain, the same class can’t be added) and we reset the first and second variables.
else {
first.classList.add('hide');
second.classList.add('hide');
setTimeout(() => {
first.classList.remove('show');
second.classList.remove('show');
first.classList.remove('hide');
second.classList.remove('hide');
first = null;
second = null;
}, 2000);
}
Conclusion
That’s it! You should have a playable memory game by now! Now you understand how to compare elements and give animations to them depend on the conditions. There’s a whole lot more you can do to explore JavaScript and CSS. You can make it multiplayer, give it flipping animations, etc.
If you want to host your result, you can do it on GitHub Pages for free or if you want it to look more professional, you can host it on Cloudways. It is a compatible, fast and reliable managed cloud hosting. Go ahead and check it out!
For you who want to brush up your JavaScript skills, whether to deepen or learn form zero, I recommend you try Codecademy. There are tons of JavaScript lessons that you can learn in a structured and interactive way. You can learn from the most basic materials to advanced stuffs and even preparing for technical interviews. Go try it now!
If you are interested to practice JavaScript by building other games, you can try my other posts :
Now, go explore! What should I build next?