
Time for action – preparing the card-matching game
Before adding the complicated game logic to our matching game, let's prepare the HTML game structure and all the CSS styles:
- Let's continue with our project. Create a new file named
matchgame.js
inside thejs
folder. - Replace the
index.html
file with the following HTML code:<!DOCTYPE html> <html lang="en"> <head> <meta charset=utf-8> <title>CSS3 Matching Game</title> <link rel="stylesheet" href="css/matchgame.css" /> </head> <body> <header> <h1>CSS3 Matching Game</h1> </header> <section id="game"> <p id="cards"> <p class="card"> <p class="face front"></p> <p class="face back"></p> </p> <!-- .card --> </p> <!-- #cards --> </section> <!-- #game --> <footer> <p>This is an example of creating a matching game with CSS3.</p> </footer> <script src="js/jquery-2.1.3.min.js"></script> <script src="js/matchgame.js"></script> </body> </html>
- In order to make the game more appealing, I prepared background images for the game table and the page. These graphic assets can be found in the code example bundle. The background images are optional, and they will not affect the gameplay and the logic of the matching game.
- We will also place the deck's sprite sheet graphics into the images folder. Then, we will download the
deck.png
file from http://mak.la/deck.png and save it within the images folder. - Create a dedicated CSS file named
matchgame.css
for our game and put it inside thecss
folder. - Now, let's add style to the matching game before writing any logic. Open
matchgame.css
and add the following body styles:body { text-align: center; background: BROWN url(../images/bg.jpg); }
- We will continue to add the styles to the
game
element. This will be the main area of the game:#game { border-radius: 10px; border: 1px solid GRAY; background: DARKGREEN url(../images/table.jpg); width: 500px; height: 460px; margin: 0 auto; display: flex; justify-content: center; align-items: center; }
- We will put all card elements into a parent DOM named
cards
. By doing this, we can easily center all the cards in the game area:#cards { position: relative; width: 380px; height: 400px; }
- For each card, we define a
perspective
property to give it a visual depth effect:.card { perspective: 600px; width: 80px; height: 120px; position: absolute; transition: all .3s; }
- There are two faces on each card. The back face will be rotated later, and we will define the transition properties to animate the style changes. We also want to make sure that the back face is hidden:
.face { border-radius: 10px; width: 100%; height: 100%; position: absolute; transition-property: opacity, transform, box-shadow; transition-duration: .3s; backface-visibility: hidden; }
- Now, we will set the styles for the front and back faces. They are almost the same as the flipping card example, except that we are now giving them background images and box shadows:
.front { background: GRAY url(../images/deck.png) 0 -480px; } .back { background: LIGHTGREY url(../images/deck.png); transform: rotate3d(0,1,0,-180deg); } .card:hover .face, .card-flipped .face { box-shadow: 0 0 10px #aaa; } .card-flipped .front { transform: rotate3d(0,1,0,180deg); } .card-flipped .back { transform: rotate3d(0,1,0,0deg); }
- When any card is removed, we want it to fade out. Therefore, we declare a card-removed class with 0 opacity:
.card-removed { opacity: 0; }
- In order to show different playing card graphics from the sprite sheet of the card deck, we clip the background of the card into different background positions:
.cardAJ {background-position: -800px 0;} .cardAQ {background-position: -880px 0;} .cardAK {background-position: -960px 0;} .cardBJ {background-position: -800px -120px;} .cardBQ {background-position: -880px -120px;} .cardBK {background-position: -960px -120px;} .cardCJ {background-position: -800px -240px;} .cardCQ {background-position: -880px -240px;} .cardCK {background-position: -960px -240px;} .cardDJ {background-position: -800px -360px;} .cardDQ {background-position: -880px -360px;} .cardDK {background-position: -960px -360px;}
- We have defined a lot of CSS styles. It is now time for JavaScript's logic. We will open the
js/matchgame.js
file and put the following code inside:$(function(){ // clone 12 copies of the card for(var i=0; i<11; i++){ $(".card:first-child").clone().appendTo("#cards"); } // initialize each card's position $("#cards").children().each(function(index) { // align the cards to be 4x3 ourselves. var x = ($(this).width() + 20) * (index % 4); var y = ($(this).height() + 20) * Math.floor(index / 4); $(this).css("transform", "translateX(" + x + "px) translateY(" + y + "px)"); }); });
- Now, we will save all the files and preview the game in the browser. The game should be well styled, and 12 cards should appear in the center. However, we cannot click on the cards yet because we have not set any interaction logic for the cards.
What just happened?
We created the game structure in HTML and applied styles to the HTML elements. You can find the working example of the game with the current progress at http://makzan.net/html5-games/card-matching-wip-step1/.
We also used jQuery to create 12 cards on the game area once the web was loaded and ready. The styles to flip and remove the cards were also prepared and will be applied to the card by using the game logic later.
Since we are using absolute positioning for each card, we need to align the cards into 4x3 tiles ourselves. In the JavaScript logic, we loop through each card and align it by calculating the position with the looping index:
$("#cards").children().each(function(index) { // align the cards to be 4x3 ourselves. var x = ($(this).width() + 20) * (index % 4); var y = ($(this).height() + 20) * Math.floor(index / 4); $(this).css("transform", "translateX(" + x + "px) translateY(" + y + "px)"); });
The % character in JavaScript is the modulus operator that returns the remainder left after pision. The remainder is used to get the column count when we loop the cards. The following diagram shows the row/column relationship with the index number:

The pision, on the other hand, is used to get the row count so that we can position the card on the corresponding row.
Take index 3 as an example; 3 % 4 is 3. So, the card at index 3 is on the third column. And 3 / 4 is 0, so it is on the first row.
Let's pick another number to see how the formula works. Let's see index 8; 8 % 4 is 0, and it is on the first column. 8 / 4 is 2 so it is on the third row.
Cloning DOM elements with jQuery
In our HTML structure, we only have one card and in the result, we have 12 cards. This is because we used the clone
function in jQuery to clone the card element. After cloning the target element, we called the appendTo
function to append the cloned card element as a child in the cards element:
$(".card:first-child").clone().appendTo("#cards");
Selecting the first child of an element in jQuery using child filters
When we selected the card element and cloned it, we used the following selector:
$(".card:first-child")
The :first-child
filter is a child filter that selects the first child of the given parent element.
Besides :first-child
, we can also select the last child by using :last-child
.
Note
You can also check other child-related selectors on the jQuery document at: http://api.jquery.com/category/selectors/child-filter-selectors/.
Vertically aligning a DOM element
We put the cards DIV in the center of the game element. CSS3 flexible box layout module introduces an easy method to achieve the vertical center alignment, as follows:
display: flex; justify-content: center; align-items: center;
The flexible box module defines the alignment of the element when there are extra spaces in the container. We can set the element to certain behaviors as a flexible box container by using the display, a CSS2 property, with the box
value, and a new CSS3 property value.
justify-content
and align-items
are two properties to define how it aligns and uses the extra free space horizontally and vertically. We can center the element by setting both properties to center
.
Vertical alignment is just a small part of the flexible box layout module. It is very powerful when you make layouts in web design. You may find further information on the W3C page of the module (http://www.w3.org/TR/css3-flexbox/) or the CSS3 tricks website (http://css-tricks.com/snippets/css/a-guide-to-flexbox/).
Using CSS sprite with a background position
The CSS sprite sheet is a big image that contains many inpidual graphics. The big sprite sheet image is applied as the background image for the elements. We can clip each graphic out by moving the background position to a fixed width and height element.
Our deck's image contains a total of 53 graphics. In order to demonstrate the background position easily, let's assume that we have an image that contains three card images, as shown in the following screenshot:

In the CSS style, we set the card element to a width of 80 px and a height of 120 px, with the background image set to the big deck image. If we want the top-left graphic, we change the values of both the x and y axes of the background position to 0. If we want the second graphic, we move the background image 80px to the left. This means setting the X position to -80px
and Y to 0. Since we have a fixed width and height, only the clipped 80 x 120 area shows the background image. The rectangle in the following screenshot shows the viewable area:
