blog | twitter | tutes | about
Creating a Mobile Friendly Picture Quiz Using HTML5
What you will learn:
Prerequisites:
Required time:
Approximately 2 hours
Notes
This will be a great project for anyone starting out in HTML5 who wants a simple and fun project to build. How about we make a picture matching quiz! We can make it easy to extend and add questions to and we can even make sure it will work on a mobile phone. And if you just want to grab the source code without following the tutorial, then that’s fine, too.
* You can view a working example here and download the completed source files here
Step 1 - Setting up the HTML document
Although you could use Dreamweaver or similar software, to create an HTML document, you don’t need any special software, you can simply use any text editor such as Textpad or Wordpad. Open your text editor and type:
This is the way that we begin all of our HTML5 documents. Now let’s fill out the document structure:
1<!DOCTYPE HTML>
2<head>
3<title>HTML5 Picture Quiz Sample</title>
4<link href="main.css" rel="stylesheet" type="text/css"/>
5<script src="jquery.js"></script>
6<script src="controller.js"></script>
7</head>
8<body>
9<div id="topbar">HTML5 Picture Quiz</div>
10<div class="spacer"></div>
11<div id="navContent">
12<div id="game1"></div>
13<div id="game2"></div>
14</div>
15</body>
16</html>
Believe it or not, that’s our whole html document, except for one line which we will add later to make it mobile-friendly.
The <title> line controls what is shown on the browser tab as the title or description of the page. [3].
The next line tells our page to look for a document called ‘main.css’ which will hold all of our style information (background colors and so on). [4].
The first <script> line tells the page to look for a JavaScript file called ‘jquery’. This is a standard JavaScript ‘extension’ widely used by developers to make JavaScript more powerful. We will not need to write this file ourselves. [5].
The second <script> line tells the page to look for a JavaScript file called ‘controller.js’. This is the file we will use to control the quiz interactivity. [6].
The next few lines, in the <body> of the page name ‘div’s or dividers that we will use to hold the page content. The ‘topbar’ will hold our page title. The ‘spacer’ div will make space on our page. ‘navContent’ holds two containers: ‘game1’ which will hold the current question and ‘game2’, which will hold the next question. [8-15].
Notice that most divs have an id, a unique identifier. One of them has a class name instead of an id name. That means we may use it more than once.
Save the document as index.html. Test it out by opening it in a browser (right-click and choose Open With and choose a browser). Obviously, there will not be much to see yet.
Step 2 – Project management
So we know that we will need the following files to build our project:
- index.html, which we have already done.
- main.css, which will hold the style information
- jquery.js, which will enhance standard JavaScript
- controller.js, which will control the quiz
We will also need images, since this is a picture quiz project, and we will need a JSON file to hold our questions. Don’t worry, just like the html, css and js pages, we can write a json file using any text editor.
Step 3 – Build a question database
Create a file in your text editor named activity.json. Then open it up and type in the following:
1{"quizlist":[
2{
3"question":"Which picture shows a lion?",
4"option1":"lion.png",
5"option2":"tiger.png",
6"option3":"cheetah.png"
7},
8{
9"question":"Which picture shows a labrador?",
10"option1":"labrador.png",
11"option2":"beagle.png",
12"option3":"poodle.png"
13},
14{
15"question":"Which picture shows a meerkat?",
16"option1":"meerkat.png",
17"option2":"chipmunk.png",
18"option3":"squirrel.png"
19}
20]
This is a JSON file and it holds data in groups. We can use it to hold our question database. You’ll notice that it is easily readable by either machine or human.
Each JSON element holds a question and three options, which are references to pictures in this case. The first option should always be the correct answer.
Later, if we wish to change or add any questions, this is the only file we will need to modify, apart from making the relevant pictures available. That means our quiz can be recycled and can even be edited by someone with very little technical expertise.
* Note that you will need to make sure that you stick very carefully to the format. A missing or extra comma, for example, can cause problems.
Save the file and continue.
Step 4 – Gather assets
From the JSON file, we see that we will have three questions and we will need three images for each, in png format (jpg or gif format will also work).
For standardisation, we want each picture to be 80x80 pixels. Different sizes will work, but will look odd on the page and may mess up the display on a small-screen mobile device.
You can obtain the images used in our sample: click here
To make things easy for ourselves, we will put all the images in a folder called img. When you upload the quiz to a website, the folder structure must be maintained. In other words, you will need to upload the entire folder.
The other asset that we need is our JQuery file. You can either get it from the source files in the link above or if you want the latest version, you could download it from jquery.com. I am using version 1.9.1. If you use a later version, be sure to shorten the name to jquery.js
Step 5 – Build a style sheet
We will use a CSS file to control the look and feel of our quiz. Later if we need to modify the look and feel, we need only modify the CSS file.
Create a document entitled main.css and open it with any text editor.
1html, body {
2margin: 0;
3padding: 0;
4background-image:url(greybg.png);
5font-family: Arial, Helvetica, sans-serif;
6}
This tells us that we will use a background image called greybg.png as the background for the entire page. (It is a small image which will repeat itself; make sure to get it from the source files and place it in your project folder.) Then unless we override it, we will use Arial font, or Helvetica or sans-serif if Arial is not available. We set margin and padding to 0 so that the page will not have any extra spacing.
1#navContent{
2margin:auto;
3width:800px;
4height:400px;
5position:relative;
6overflow:hidden;
7}
8
9#game1{
10margin:auto;
11width:800px;
12height:400px;
13right:0px;
14position:absolute;
15}
16
17#game2{
18margin:auto;
19width:800px;
20height:400px;
21right:-800px;
22position:absolute;
23}
navContent will be our outer container, holding game1 and game2, which will contain the current and next questions.
We want our quiz to be 800 pixels wide, 400 pixels in height and centered horizontally on the page (margin:auto). Anything that ‘sticks out’ of this area will be hidden (overflow:hidden). ‘game2’ will begin outside of this area (right:-800px) and hence will be hidden.
In CSS, we refer to an ID name by a hashtag (#) and we refer to a class name by a dot (.). Remember, we expect to reuse class names for multiple elements, but the ID name should refer to a unique element. Some standardised elements (body/html) are referred to directly.
Let’s continue:
1.questionText{
2font-size:18px;
3color:#FFF;
4}
5
6.pix{
7width:80px;
8height:80px;
9margin:15px;
10float:left;
11border: 5px solid white;
12cursor:pointer;
13}
14
15.pix:hover{
16border:#FC0 solid 5px;
17}
We define our question text font-size and color (#fff is white). If you need a reference for color codes, try colorpicker.com
We want our pictures to be 80x80 pixels. We need a margin of 15 pixels just to space them out. We should show them side-by-side (float:left) with a white border. We should show a pointer so that the user knows they are clickable (cursor:pointer).
When the user mouses over a picture, the border should turn yellow, for a nice effect.
Now for a couple of miscellaneous items:
1#topbar{
2height:100px;
3margin:auto;
4margin-top:50px;
5color:#FFF;
6font-size:36px;
7font-family:Arial, Helvetica, sans-serif;
8width:800px;
9}
10
11.spacer{
12height:30px;
13}
‘topbar’ will hold our title, which you can check looking back at the HTML file. ‘spacer’ simply adds a little space between the title and the beginning of the quiz.
Although we are not reusing ‘spacer’, we define it as a class because we might reuse it in other projects. A good designer always produces recyclable content and CSS files are very easy to reuse.
Let’s finish off our CSS:
1.feedback1{
2width:150px;
3padding:5px;
4font-size:30px;
5color:#FFFFCC;
6background-color:#009900;
7font-family:Arial, Helvetica, sans-serif;
8text-align:center;
9position:absolute;
10top:170px;
11}
12
13.feedback2{
14width:150px;
15padding:5px;
16font-size:30px;
17color:#FFFFCC;
18background-color:#CC3300;
19font-family:Arial, Helvetica, sans-serif;
20text-align:center;
21position:absolute;
22top:170px;
23}
We will use ‘feedback1’ and ‘feedback2’ to style two messages: CORRECT and WRONG depending on whether the user gets the question right or not. You can see that the only difference between the two styles is that one has a green background [6] and the other has a red background [18].
We will position the messages 170 pixels from the top of their container (top:170px).
That will do for the CSS for now. We will add some more later to ensure the quiz works on a mobile phone.
Step 6 – Creating the JavaScript code
Well, so far we’ve done a lot of work and we have little to show for it! We’d better remedy that.
Create a document called controller.js, save it and open it with a text editor or other program.
1$(document).ready(function () {
2
3
4});
This is how we begin and all of our code will fall between these two lines. It basically says that we will do the following as soon as the document is ‘ready’ in the browser.
We’ll begin by defining the various variables we will need to use:
1var questionNumber=0;
2var questionBank=new Array();
3var stage="#game1";
4var stage2=new Object;
5var questionLock=false;
6var numberOfQuestions;
7var score=0;
We will always try to keep our variables ‘human and machine readable’. For example, we can see the variable numberOfQuestions refers to the number of questions. Following this principle makes it really easy to read your code.
An array is a series of variables. For example, if a=["tiger","lion","panther"] then a[0] is tiger, a[1] is lion and so forth.
‘stage’ and ‘stage2’ are objects that we will use to refer to the containers for the current and next questions.
Right then, we need to get the data from our JSON file into a useable format in controller.js. Here’s how:
1$.getJSON('activity.json', function(data) {
2
3for(i=0;i<data.quizlist.length;i++){
4questionBank[i]=new Array;
5questionBank[i][0]=data.quizlist[i].question;
6questionBank[i][1]=data.quizlist[i].option1;
7questionBank[i][2]=data.quizlist[i].option2;
8questionBank[i][3]=data.quizlist[i].option3;
9}
10numberOfQuestions = questionBank.length;
11alert(questionBank);
12})//gtjson
We use the command $.getJSON to read our JSON data and call a function to format it. The $.getJSON() command is an example of a function from JQUERY. Without our JQUERY extension, we would not be able to use this code. Code that begins with a ‘$’ references JQUERY.
We loop through all the JSON elements inside the quizlist element, ie all of our questions. Then we use the data to form an array of information called questionBank. We are using a two-dimensional array here:
One dimensional array: questionBank = ["cat","dog","fox"]; (questionBank[1]= "dog")
Two dimensional array: questionBank=[["cat", "dog", "fox"], ["lion", "tiger", "zebra"],[ "kangaroo", "koala", "wallaby"]]; (questionBank[1][2]= "zebra")
Once the array is full, we can use its length to determine the number of questions [10]. The next line, alert(questionBank); is only for testing; it will display the contents in an alert (pop up) window.
Now would be a good time to test the app. Right-click on index.html and open it in Firefox, or Internet Explorer. (*Note – since we are using JSON, Chrome will not work when OFFLINE. When hosted on a website, Chrome will work.) You should see a pop up window displaying the contents of the database, as shown below. If not, review the code so far to check for mistakes.
Step 7 – Displaying the questions
Find the line that says alert(questionBank);
Delete it and in its place add:
displayQuestion()
This will call the function to display a question. We will write this function now. It can be placed immediately after the previous code that ends with the line: })//gtjson
1function displayQuestion(){
2var rnd=Math.random()*3;
3rnd=Math.ceil(rnd);
4var q1;
5var q2;
6var q3;
7
8if(rnd==1){q1=questionBank[questionNumber][1]; q2=questionBank[questionNumber][2]; q3=questionBank[questionNumber][3];}1
9if(rnd==2){q2=questionBank[questionNumber][1]; q3=questionBank[questionNumber][2]; q1=questionBank[questionNumber][3];}
10if(rnd==3){q3=questionBank[questionNumber][1];q1=questionBank[questionNumber][2];q2=questionBank[questionNumber][3];}
11
12$(stage).append('<div class = "questionText">' + questionBank[questionNumber][0] + '</div><div id="1" class="pix"><img src="img/'+q1+'"></div><div id="2" class="pix"><img src="img/'+q2+'"></div><div id="3" class="pix"><img src="img/'+q3+'"></div>');
13
14$('.pix').click(function(){
15if(questionLock==false){questionLock=true;
16//correct answer
17if(this.id==rnd){
18$(stage).append('<div class="feedback1">CORRECT</div>');
19score++;
20}
21//wrong answer
22if(this.id!=rnd){
23$(stage).append('<div class="feedback2">WRONG</div>');
24}
25//setTimeout(function(){changeQuestion()},1000);
26}})
27}//display question
First of all we declare a variable rnd and use it to generate a random number between 0 and 2 [2]. We then round up this number using Math.ceil() so that we are left with an integer between 1 and 3. We will use this random number to choose the pattern in which the pictures are displayed. If rnd is equal to one, then q1 refers to the first picture, which is also the answer. If rnd is equal to two, then q2 is the answer and q1 and q3 are the distractor options, and so on.
The next line is very important to understand. We are going to add content to the ‘stage’, which references #game1. We add HTML content to the page dynamically through our code, first adding the question text and then adding the pictures and formatting information [12]. Note that each picture is assigned an ID of 1,2 or 3. We will use this ID to check the answer.
We then add a ‘listener’ to the class ‘.pix’ [14-26]. That means it will attach to all three pictures on the screen. This listener will detect a ‘click’ – but it will also detect a touch even on a mobile device.
We need a mechanism to ‘lock’ the question so that, once answered, it cannot be answered again [15/26]. Hence we have the variable questionLock. If it is false, we set it to true and check the answer. If it is already set to true, the next part is ignored.
To check the answer, we use the line:
if(this.id==rnd){}
In this case ‘this’ is the element which was clicked and this.id is the id number we gave the element. The way we set up the options, if the id number coincides with our variable rnd, it is the correct answer. If not, it is the wrong answer:
if(this.id!=rnd){}
In JavaScript (and most other coding languages), != means ‘does not equal’.
If the answer is correct, we add another piece of HTML, a <div> of the class feedback1 (green background) containing the text CORRECT [18]. We then increment the score (score++;) [19].
If the answer is wrong, we add a <div> of class feedback2 (red background) and the text WRONG [23].
We then have a line of code beginning with setTimeout(). We will ignore this for just a moment. The two slashes (//) at the beginning of a line are used for comments, but we can also use them to temporarily disable code.
Now would be a great time to test what we have so far. Open index.html in your browser and you should see this:
Keep in mind that the answers are randomised, so you may see the pictures in a different order. Now try clicking on the correct answer:
And then, refresh the page and try clicking on the wrong answer. Is everything working? If not, go back and check the code. If so, let’s carry on.
Step 8 – Transitioning the questions
Next, we need to have a way of moving on to the next question. How we are going to this is to wait one second after the answer has been selected, then move this question offscreen to the left while bringing in the new question onscreen from the right.
First reenable this line of code by removing the double slashes:
setTimeout(function(){changeQuestion()},1000);
This line tells us to wait for 1000 milliseconds (one second) and then perform the function changeQuestion(). We haven’t written the function changeQuestion yet, so we’d better do it:
1function changeQuestion(){
2
3questionNumber++;
4
5if(stage=="#game1"){stage2="#game1";stage="#game2";}
6else{stage2="#game2";stage="#game1";}
7
8if(questionNumber < numberOfQuestions){displayQuestion();}
9//else{displayFinalSlide();}
10
11$(stage2).animate({"right": "+=800px"},"slow", function() {$(stage2).css('right','-1800px');$(stage2).empty();});
12$(stage).animate({"right": "+=800px"},"slow", function() {questionLock=false;});
13}//change question
There we go. The first thing is to increase the variable that tracks the question number [3].
On the next two lines, we perform a switcheroo. If our stage variable points to #game1, we switch it to #game2 and vice versa. Likewise with a second variable stage2 [5-6].
We are always going to use stage to bring the new question in and use stage2 to remove the old question.
The next line checks whether (questionNumber < numberOfQuestions). If so, we can load up the next question, recycling the function we used before (displayQuestion). If not, we will display our final slide. The last part is temporarily disabled so we can test this function.
We then use a piece of code from JQUERY, animate, to transition the page elements, giving the direction, speed and running a function when the transition is complete [11-12].
When the transitions are complete, we move stage2 back offscreen to the right by amending its CSS property $(stage2).css('right' , '-800px'); We then empty its contents ($(stage2).empty();) and it will sit there waiting for the next question [11-12].
When stage1 has completed its transition, we remove the question lock (questionLock=false) so that the next question can be answered.
This mechanism we have built can be used to cycle through all the questions. Test it out now.
Step 9 – Ending it
We should display a score page when the quiz has ended. In the previous code, make sure this line is fully enabled by removing the double slashes:
else{displayFinalSlide();}
Then we need to flesh out the last part of our Javascript code thus:
1functiondisplayFinalSlide(){
2
3$(stage).append('<div class="questionText">You have finished the quiz!<br><br>Total questions: '+numberOfQuestions+'<br>Correct answers: '+score+'</div>');
4
5}//display final slide
Well, that’s short and sweet. For the final page, we will append a piece of code that offers a message and tells us our score, using the variable we have been tracking[3].
We have recycled the class ‘questionText’ for the styling, which is technically a no-no because it could confuse people reading the code. But just this once it should be fine; let’s save ourselves some work. Note that we use the simple technique of adding line breaks (<br>) to space the message out nicely.
Now try running the quiz again and after three questions, you should get a page like this:
Step 10 – Making it work in mobile
Well, our quiz is now working. Hooray!
But wait, there more, as they like to say on the TV ads. With a few more lines of code, we can make sure that the quiz can work on a small screen, such as a phone.
You can do a basic test with your browser by dragging the edge with your mouse until it is narrow, like a phone screen. You will see something like the image here:
See? It sticks out because some parts of the page have a width of 800 pixels. But to work on a phone, we want it to work down to a width of about 320 pixels – the width of an iPhone.
Our solution is something called ‘media queries’. We can set different CSS rules depending on the width of the screen.
At the end of our CSS file, let’s add:
1@media screen and (max-width:800px) {
2#topbar{margin-left:1%;margin-right:1%;width:98%;}
3#navContent{margin:1%;width:98%;}
4#game1{margin:1%;width:98%;}
5#game2{margin:1%;width:98%;}
6}
7
8@media screen and (max-width:400px) {
9.pix{margin:1px;margin-top:10px;}
10}
To make a long story short, wherever we have a width of 800 pixels, when the width is less than 800px, we change the rules to percentages, so that it will fill 98% of the container with a 1% margin on each side [1-6].
Then, because our pictures are 80x80, we need to decrease the margin in between them when the screen is small. We’ll do it when the screen is smaller than 400 pixels wide [8-10].
Hence, 800 and 400 are our ‘breakpoints’, since the layout will be redefined (slightly) at these widths.
To avoid issues with Android phones, we need to go back to the index.html file and add this line in the <head> section:
And we’re done! Phew! It was a long journey, but along the way we learned HTML5, CSS, JavaScript and JSON techniques.
And you have working, recyclable code for a picture matching game.
I hope you enjoyed learning from this tutorial. Remember to check out more tutorials at www.flashbynight.com/tutes
We also have some great games for you at www.flashbynight.com so stop by and check them out.
If you like this tutorial or anything else on Flash By Night, please show your love by mentioning it on Facebook, Twitter, Pinterest, StumbleUpon or any other favorite social media.