Creating Flip Card Memory Game with HTML, CSS, and JavaScript

Faraz

By Faraz -

Learn how to create a flip card memory game or card matching game using HTML, CSS, and JavaScript with this step-by-step guide.


creating flip card memory game with html, css, and javascript.jpg

Table of Contents

  1. Project Introduction
  2. HTML Code
  3. CSS Code
  4. JavaScript Code
  5. Preview
  6. Conclusion

Memory games are a fun way to challenge your brain and improve your cognitive skills. In this blog post, we will guide you on creating a flip card memory game using HTML, CSS, and JavaScript.

Memory games are played by flipping over cards to reveal their hidden images and trying to match pairs of identical images. This game is a classic way to test and improve your memory skills, and building your own version of the game is a great way to improve your programming skills.

In this blog post, we will provide a step-by-step guide on how to create a memory game by flipping cards using HTML, CSS, and JavaScript. We will start with the prerequisites, which include basic knowledge of HTML, CSS, and JavaScript, a text editor or code editor, and a web browser.

By the end of this blog post, you will have all the knowledge you need to create your own flip card memory game. We will break down the process into easy-to-follow steps, and provide screenshots and code snippets to make it easier for you to understand.

Let's start making a fantastic flip card memory game/card matching game using HTML, CSS, and JavaScript step by step.

Join My Telegram Channel to Download the Project: Click Here

Source Code

Step 1 (HTML Code):

To get started, we will first need to create a basic HTML file. In this file, we will include the main structure for our memory game.

After creating the files just paste the following below codes into your file. Make sure to save your HTML document with a .html extension, so that it can be properly viewed in a web browser.

This is an HTML file that contains the code for a flip card memory game. HTML (Hypertext Markup Language) is a markup language used to create web pages.

The code starts with the document declaration: <!DOCTYPE html>. This tells the web browser which version of HTML to use. The html tag is the root element of the HTML document, and the lang attribute specifies the language of the document, in this case, English.

The head section contains metadata about the document, such as the title of the web page, which is displayed on the browser tab, and the description, which provides a summary of the page's content to search engines. The viewport meta tag sets the width of the page to fit the device's screen size, while the charset meta tag specifies the character encoding of the document.

The link tags in the head section refer to external CSS (Cascading Style Sheets) files used to style the page. The first link refers to an icon font called Font Awesome, while the second link imports two Google Fonts: Concert One and Nova Slim. The third link imports a CSS file called styles.css, which contains custom styles for the page.

The body section contains the content of the page. The container div is a wrapper for the entire content of the page. The header section contains the title of the game. The section with class "score-table" displays the game statistics, including the player's current score (indicated by stars), the number of moves, and the elapsed time. The div with class "restart" allows the player to restart the game at any time.

The main section contains the game board, represented by an unordered list with class "deck". Each list item contains a pair of cards, and when clicked, the card flips over to reveal its symbol. The player must match pairs of cards with identical symbols to win the game.

Finally, the div with class "modal" is a popup window that appears when the player wins the game. It contains a congratulatory message.

This is the basic structure of our card matching game using HTML, and now we can move on to styling it using CSS.

Step 2 (CSS Code):

Once the basic HTML structure of the memory game is in place, the next step is to add styling to the flip card using CSS. CSS allows us to control the visual appearance of the website, including things like layout, color, and typography.

Next, we will create our CSS file. In this file, we will use some basic CSS rules to create our matching card.

The CSS code contains various rules that define the layout and styling of the game's different elements, such as the game board, cards, and modal window.

The first few rules define the box-sizing property for the HTML element and its children elements. The box-sizing property sets how the width and height of an element are calculated, and by setting it to border-box, the total width and height of an element includes its content, padding, and border.

The next few rules set some basic styles for the HTML and body elements, such as setting their width and height to 100%, and removing any default margin and padding.

The .container class sets the display property to flex and aligns its child elements both horizontally and vertically.

The .score-table class defines the layout of the game's score table. It sets the width to 500px, and uses flexbox to align the table elements in a row with space-around alignment.

The .stars class sets the display property to flex and sets the list-style to none, which removes the bullet points from any list items.

The .restart class sets the cursor property to pointer, which changes the cursor to a pointer icon when the user hovers over it.

The .deck class styles the game board by setting a linear gradient as the background color, adding a box shadow and border radius to the board, and setting the display property to flex. It also sets the width and minimum height of the board and uses flexbox to align the cards in rows with space-around alignment.

The .card class styles the individual memory cards by setting the size, background color, box shadow, font size, and display property. It also defines the transform property to rotate the cards when they are flipped, and sets a transition duration of 0.5 seconds for the transform effect.

The .show class defines the style for the flipped cards, setting the background color, font size, and color.

The .match class defines the style for matching cards, changing the background color to a green color.

The .no-match class defines the style for non-matching cards, changing the background color to a red color.

The .modal class styles the modal window that appears when the game is completed. It sets the position to fixed, and the background color to a semi-transparent gray color. The opacity and visibility are set to 0 and hidden respectively, and the transform property is used to scale the modal window when it appears. The transition property is used to define the transition effect when the modal window appears.

The .modal-content class styles the content of the modal window by setting its position to absolute, and aligning it in the center of the screen using the transform property. It also sets the width and padding of the modal content and adds a border radius.

The .close-button class styles the close button of the modal window, setting its position to float right and adding some padding and border radius.

The .show-modal class is used to make the modal window visible, changing the opacity and visibility to 1 and scaling it to its original size.

Lastly, the @media rule sets the layout of the game elements for screens with a maximum width of 600px, changing the size of the game board and cards, as well as adjusting the font sizes and width of the score table.

This will give our flip card memory game an upgraded presentation. Create a CSS file with the name of styles.css and paste the given codes into your CSS file. Remember that you must create a file with the .css extension.

html {
  box-sizing: border-box;
}

*, *::before, *::after {
  box-sizing: inherit;
}

html, body {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}

body {
  font-family: 'Concert One', 'Coda', san-serif, cursive;
}

.container {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

.score-table {
  text-align: left;
  width: 500px;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  align-items: center;
}

.stars {
  display: flex;
  list-style: none;
}

.restart {
  cursor: pointer;
}

.deck {
  background: linear-gradient(135deg, rgba(207, 197, 229, 1) 0%, rgba(163, 154, 204, 1) 36%, rgba(79, 71, 169, 1) 100%);
  margin: 0;
  width: 612px;
  min-height: 500px;
  box-shadow: 10px 9px 31px 1px rgba(0, 0, 0, 0.75);
  border-radius: 10px;
  display: flex;
  justify-content: space-around;
  flex-wrap: wrap;
  padding: 20px;
  margin-bottom: 15px;
  align-items: center;
}

.card {
  transform: rotateY(0);
  transition: 0.5s;
  width: 125px;
  height: 125px;
  background: linear-gradient(to bottom, rgba(69, 72, 77, 1) 0%, rgba(0, 0, 0, 1) 100%);
  box-shadow: 5px 5px 24px -3px rgba(0, 0, 0, 0.75);
  border-radius: 8px;
  font-size: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  list-style: none;
  margin-top: 15px;
  cursor: pointer;
}

.show {
  transform: rotateY(180deg);
  transition: 0.5s;
  background: skyblue;
  font-size: 33px;
  color: white;
  cursor: default;
}

.match {
  background: rgb(4, 172, 54);
}

.no-match {
  background: rgb(175, 38, 38);
  transition: 0.1s;
}

.modal {
  z-index: 1;
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.6);
  opacity: 0;
  visibility: hidden;
  transform: scale(1.1);
  transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;
}

.modal-content {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: rgb(241, 241, 241);
  padding: 1rem 1.5rem;
  width: 35rem;
  border-radius: 0.5rem;
  text-align: center;
}

.close-button {
  float: right;
  width: 1.5rem;
  line-height: 1.5rem;
  text-align: center;
  cursor: pointer;
  border-radius: 0.25rem;
  background-color: lightgray;
}

.close-button:hover {
  background-color: darkgray;
}

.show-modal {
  opacity: 1;
  visibility: visible;
  transform: scale(1.0);
  transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;
}

.tick {
  color: rgba(0, 218, 29, 0.767);
  font-size: 60px;
  margin-left: 35px;
}

.modal-heading {
  letter-spacing: 2px;
}

.stats {
  color: rgb(143, 143, 143);
  margin-top: 30px;
}

.new-game {
  background: rgb(75, 189, 0);
  color: #fff;
  border: 0;
  padding: 1em 2em;
  font-size: 1.2em;
  cursor: pointer;
  margin-top: 25px;
}

@media screen and (max-width: 600px) {
  .deck {
      width: 350px;
      min-height: 280px;
  }
  .card {
      width: 68px;
      height: 68px;
  }
  .show{
      font-size: 30px;
  }
  .modal-content {
      width: 15rem;
  }
  .tick {
      color: rgba(0, 218, 29, 0.767);
      font-size: 45px;
      margin-left: 25px;
  }
  h1 {
      font-size: 20px;
  }
  h3 {
      font-size: 16px;
  }
  .score-table {
      width: 320px;
  }
} 

Step 3 (JavaScript Code):

The game has features like keeping track of the number of moves, a star rating system, a timer, and a restart button. The game logic is implemented using various functions that are called at different events such as card click, win condition, etc. Here are some of the main functions used in the game:

shuffle(array): This function shuffles the elements of an array in a random order. It uses a while loop to iterate through the array and swap each element with another randomly selected element.

toggleModal(): This function toggles the visibility of a modal box, which is displayed when the player wins the game. It is called when the player clicks on the close button or anywhere outside the modal box.

windowOnClick(event): This function is called when the player clicks anywhere on the window. If the clicked element is the modal box, it calls the toggleModal() function to hide the modal.

createCards(): This function creates a deck of cards by dynamically creating HTML elements using JavaScript. It uses a loop to iterate through the shuffled array of symbols and creates a new list item for each symbol.

initGame(): This function initializes the game by calling the createCards() function to generate the deck of cards, and adding event listeners to each card for the click event. It also initializes the variables for the number of moves, star rating, timer, and restart button.

showCard(card): This function adds the "show" class to a clicked card element, which displays the symbol of the card.

addCard(card, cardHTML, testList, pos): This function is called when two cards are clicked. It adds the clicked card and its corresponding HTML element to an array called testList. If the length of testList is 6, it calls the testCards() function to check if the selected cards are a match or not.

testCards(card1, html1, x1, card2, html2, x2): This function is called when two cards are selected for testing. It compares the symbols of the two cards and if they match, it calls the cardsMatch() function. Otherwise, it calls the cardsDontMatch() function.

cardsMatch(card1, card2): This function adds the "match" class to the selected cards, which displays them as a matched pair. It also increments the match variable, and if all pairs are matched, it calls the win() function.

cardsDontMatch(card1, card2): This function adds the "no-match" class to the selected cards, which displays them briefly as red to indicate they are not a match. It removes the "show" class from the selected cards, hiding their symbols again.

win(): This function is called when all pairs are matched. It stops the timer, displays a modal box with the player's stats, and calls the toggleModal() function to show the modal.

updateMoveCounter(): This function increments the move counter, updates the moves display, and adjusts the star rating based on the number of moves.

timer(): This function updates the elapsed time display every second. It increments the seconds variable and calculates the minutes based on the number of seconds.

Create a JavaScript file with the name of script.js and paste the given codes into your JavaScript file and make sure it's linked properly to your HTML document, so that the scripts are executed on the page. Remember, you’ve to create a file with .js extension.

function shuffle(array) {
  var currentIndex = array.length, temporaryValue, randomIndex;

  while (currentIndex !== 0) {
      randomIndex = Math.floor(Math.random() * currentIndex);
      currentIndex -= 1;
      temporaryValue = array[currentIndex];
      array[currentIndex] = array[randomIndex];
      array[randomIndex] = temporaryValue;
  }

  return array;
}

const modal = document.querySelector(".modal");
const closeButton = document.querySelector(".close-button");

function toggleModal() {
  modal.classList.toggle("show-modal");
}

function windowOnClick(event) {
  if (event.target === modal) {
      toggleModal();
  }
}

closeButton.addEventListener("click", toggleModal);
window.addEventListener("click", windowOnClick);

let cardTest = [];
let cards = ["diamond", "diamond", "plane", "plane", "anchor", "anchor", "bolt", "bolt", "leaf", "leaf"
  , "bicycle", "bicycle", "cube", "cube", "bomb", "bomb"];

let shuffledCards = shuffle(cards);

function createCards() {
  for (let card of shuffledCards) {
      const li = document.createElement("LI");
      li.classList.toggle("card");
      const i = document.createElement("i");
      i.classList.toggle("fa");
      if (card === "plane") {
          i.classList.toggle("fa-paper-plane-o");
      } else {
          i.classList.toggle("fa-" + card);
      }
      const deck = document.querySelector('.deck');
      li.appendChild(i);
      deck.appendChild(li);

  }
}

const ul = document.querySelector('.deck');
let moves = document.querySelector(".moves");
let movesCounter = 0;
let stars = 3;
let match = 0;
let isfirstClick = true;
let timerID;
let isRestart = false;

function initGame() {
  createCards();
  const card = document.querySelectorAll('.card');
  for (let i = 0; i < card.length; i++) {
      card[i].addEventListener("click", function (event) {
          if (card[i] !== event.target) return;
          if (event.target.classList.contains("show")) return;
          if (isfirstClick) {
              timerID = setInterval(timer, 1000);
              isfirstClick = false;
          }
          showCard(event.target);
          setTimeout(addCard, 550, shuffledCards[i], event.target, cardTest, i);
      }, false);
  }
}

function showCard(card) {
  card.classList.add('show');

}

function addCard(card, cardHTML, testList, pos) {
  if (isRestart) {
      testList.length = 0;
      isRestart = false;
  }
  testList.push(card);
  testList.push(cardHTML)
  testList.push(pos);
  if (testList.length === 6) {
      updateMoveCounter();
      testCards(testList[0], testList[1], testList[2], testList[3], testList[4], testList[5]);
      testList.length = 0;
  }
}

function testCards(card1, html1, x1, card2, html2, x2) {
  if (card1 === card2 && x1 != x2) {
      cardsMatch(html1, html2);
  } else {
      cardsDontMatch(html1, html2);
  }
}

function cardsMatch(card1, card2) {
  card1.classList.add('match');
  card2.classList.add('match');
  match++;
  if (match === 8) {
      win();
  }
}

function cardsDontMatch(card1, card2) {
  card1.classList.toggle('no-match');
  card2.classList.toggle('no-match');
  setTimeout(function () {
      card1.classList.toggle('no-match');
      card2.classList.toggle('no-match');
      card1.classList.toggle('show');
      card2.classList.toggle('show');

  }, 300);
}

function win() {
  clearInterval(timerID);
  toggleModal();
  const stats = document.querySelector(".stats");
  if (s % 60 < 10) {
      stats.textContent = "You won with: " + stars + " stars in " + movesCounter + " moves with time: " + m + ":0" + s % 60;
  } else {
      stats.textContent = "You won with: " + stars + " stars in " + movesCounter + " moves with time: " + m + ":" + s % 60;
  }
}

function updateMoveCounter() {
  movesCounter++;
  moves.textContent = "Moves: " + movesCounter;
  if (movesCounter === 13) {
      let star = document.querySelector("#star3");
      star.classList.toggle("fa-star");
      star.classList.add("fa-star-o");
      stars--;
  } else if (movesCounter === 25) {
      let star = document.querySelector("#star2");
      star.classList.toggle("fa-star");
      star.classList.add("fa-star-o");
      stars--;
  } else if (movesCounter === 35) {
      let star = document.querySelector("#star1");
      star.classList.toggle("fa-star");
      star.classList.add("fa-star-o");
      stars--;
  }
}

let s = 0; 
let m = 0; 
function timer() {
  ++s;
  m = Math.floor(s / 60);
  let timer = document.querySelector(".timer");
  if (s % 60 < 10) {
      timer.textContent = "Elapsed Time: " + m + ":0" + s % 60;
  } else {
      timer.textContent = "Elapsed Time: " + m + ":" + s % 60;
  }

}

let restart = document.querySelector(".restart");
restart.addEventListener("click", restartGame, false);
function restartGame() {
  clearInterval(timerID);
  movesCounter = 0;
  match = 0;
  s = 0;
  m = 0;
  isfirstClick = true;
  isRestart = true;
  const deck = document.querySelector('.deck');
  var elements = deck.getElementsByClassName("card");

  while (elements[0]) {
      elements[0].parentNode.removeChild(elements[0]);
  }
  shuffledCards = shuffle(cards); 
  let timer = document.querySelector(".timer");
  timer.textContent = "Elapsed Time: 0:00";
  moves.textContent = "Moves: " + movesCounter;

  resetStars();
  initGame();
}

function resetStars() {
  stars = 3;
  let star = document.querySelector("#star3");
  star.classList.remove("fa-star");
  star.classList.remove("fa-star-o");
  star.classList.add("fa-star");

  star = document.querySelector("#star2");
  star.classList.remove("fa-star");
  star.classList.remove("fa-star-o");
  star.classList.add("fa-star");

  star = document.querySelector("#star1");
  star.classList.remove("fa-star");
  star.classList.remove("fa-star-o");
  star.classList.add("fa-star");
}

const newGameButton = document.querySelector(".new-game");
newGameButton.addEventListener("click", newGame);
function newGame() {
  toggleModal();
  restartGame();
}

initGame();

Final Output:

creating flip card memory game with html, css, and javascript.gif

Conclusion:

Throughout this blog post, we have provided a step-by-step guide on how to create a memory game with flipping cards. We started with the prerequisites, which included basic knowledge of HTML, CSS, and JavaScript, a text editor or code editor, and a web browser.

We then covered the HTML structure, CSS styling, and JavaScript functionality needed to create the game. We provided code snippets and screenshots to illustrate each step, making it easier for you to follow along.

Remember that this is just the beginning of your programming journey. Keep practicing and exploring new ideas. The best way to improve your programming skills is to continue building projects, challenging yourself, and experimenting with new techniques.

We hope this tutorial has been helpful in your journey to become a better programmer. If you have any questions or suggestions, please leave a comment below.

That’s a wrap!

I hope you enjoyed this post. Now, with these examples, you can create your own amazing page.

Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee.

And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!

Thanks!
Faraz 😊

End of the article

Subscribe to my Newsletter

Get the latest posts delivered right to your inbox


Latest Post