
In this article we’re going to introduce you to functions and arrays. We’re also going to see a bit more of the browser’s document object model (DOM) and how it can be leveraged using JavaScript. And, not to disappoint you, we’re going to build something cool with everything that you learn: a revolving photo slideshow page.
Let’s first take a look at the slideshow page so you understand what we’re going to build. You might have seen a few of these on hipper sites across the web. They usually consist of a full-screen image used in the background, with text placed over the image. Often these automatically, or by user input, switch between a set of images. These types of pages are being used for homepages, on photo sites and even as album cover viewers, complete with background audio (we’ll look at audio later in the series when we cover HTML5 APIs).
Download the accompanying tutorial files and open the file ‘slideshow.html’ to see the completed example. Does it look like this would be complicated to build? Not at all! We’ll supply all the code and instruction you need.
tools | tech | trends: Text editor (eg Dreamweaver, TextMate, NotePad or equivalent) plus web browser
experts: Elisabeth Robson, Eric Freeman
tutorial files: download here
01. The HTML markup
We’ll start with a simple HTML page. The body contains two <div>s, the first of which will be used for the page background (lines 8-9), and a second <div> that is used to hold the descriptive text that will be placed on top of the background (lines 10-11).
001 <!doctype html> 002 <html> 003 <head> 004 <title>Beautiful Food Photo Slideshow</title> 005 <meta charset="utf-8"> 006 <link rel="stylesheet" href="slideshow. css"> 007 <script src="slideshow.js"></script> 008 </head> 009 <body> 010 <div> 011 <img id="one"> 012 <img id="two"> 013 </div> 014 <div id="description"> 015 </div> 016 </body> 017 </html>
02. Add the images
Now add two images to the divs; we’ll need both of these to smoothly fade one image out as we fade another in (we’ll get to the fading effect in a bit). If you’re used to HTML you might have noticed there are no src attributes in the <img> tags (lines 2, 3), and that’s because we’re going to specify the image sources, dynamically, with JavaScript.
001 <div> 002 <img id="one"> 003 <img id="two"> 004 </div>
03. Add the JavaScript
Rather than placing JavaScript code directly into this page, we’ll use the <script> element’s src attribute to point to the file slideshow.js (line 4), where we’ll write the code. This lets us keep our HTML and JavaScript separate, which is often more maintainable and readable. It’s important that you specify a closing </script> tag or you’ll get unwanted behaviour from some browsers.
001 <head> 002 <title>Beautiful Food Photo Slideshow</title> 003 <meta charset="utf-8"> 004 <script src="slideshow.js"></script> 005 </head>
04. Add the CSS
Add a link to a CSS file named slideshow.css (line 4), which uses some newer features of CSS3 to handle the visual transition from image to image; we’ll take a closer look at the CSS next.
001 <head> 002 <title>Beautiful Food Photo Slideshow</title> 003 <meta charset="utf-8"> 004 <link rel="stylesheet" href="slideshow.css"> 005 <script src="slideshow.js"></script> 006 </head>
05. Make the photos full screen
In slideshow.css first make sure the photo <div> fills the entire screen (lines 1-6), and position it (lines 7-9). Then set the images to fill the entire screen, and make sure they are sized appropriately for any browser window size, by setting the min-width and min-height properties of the image to 100% (lines 9-10), setting the width and height to auto (lines 12-13), and positioning them (lines 15-17).
001 html, body, div.photo {
002 width: 100%;
003 padding: 0px;
004 margin: 0px;
005 }
006 position: relative;
007 }
008 img {
009 min-width: 100%;
010 min-width: 100%;
011
012 width: auto;
013 height: auto;
014
015 position: fixed;
016 top: 0px;
017 left: 0px;
018 }
06. Handle the transitions
To handle the fade in/out between the images, we’re using a CSS3 property, transition (lines 9-14) to affect the opacity of the photo. We’re specifying the opacity in the img.transparent rule, so the transition will happen when an element has the class ‘transparent’. In the img.transparent rule, we specify an opacity of 0 (in other words, completely transparent). That means whenever we add the class transparent to an image, the transition will be applied and the image will transition from fully opaque to fully transparent over one second. The easing method – ease-in-out – specifies that the transition should happen in a gentle, slow start and finishing manner. We’ll be setting the class of the image using JavaScript so we can control when this fading transition occurs.
001 img {
002 min-width: 100%;
003 min-height: 100%;
004 width: auto;
005 height: auto;
006 position: fixed;
007 top: 0px;
008 left: 0px;
009 // We still need browser-specific versions of the transition, be careful to use this ordering
010 -webkit-transition: opacity 1s ease-in-out;
011 -moz-transition: opacity 1s ease-in-out;
012 -o-transition: opacity 1s ease-in-out;
013 -ms-transition: opacity 1s ease-in-out;
014 transition: opacity 1s ease-in-out;
015 }
016 img.transparent {
017 opacity: 0;
018 }
07. Style the description
Now position the description <div> so it sits on top of the photo near the bottom-left of the screen.
001 div#description {
002 position: absolute;
003 font-family: Helvetica, sans-serif;
004 font-size: 600%;
005 font-weight: bold;
006 color: white;
007 text-shadow: 1px 1px 3px #373737;
008 left: 30px;
009 bottom: 30px;
010 }
08. Create arrays to hold image names and text
Now that you’ve created the HTML and CSS, you need to add the behaviour using JavaScript. First you’re going to define a set of images with corresponding descriptions, and to do that we’ll use a data type called an array. You’ll create two arrays: one to hold the image names for the photos, and the second to hold the string description we’ll display on top of each photo.
001 var photos = [ 002 "images/Pears.jpg", 003 "images/Salad.jpg", 004 "images/Cauliflower.jpg" 005 ]; 006 var descriptions = [ 007 "Asian Pears", 008 "Spinach Salad", 009 "Romanesque Cauliflower" 010 ];
09. Set the Image src attribute with JS
Now you’re ready to use the arrays to set the src images of the <img> elements in the HTML. To do that you’ll use document.getElementById() to get an <img> element and then set its src. Here we’ve initially set the src of the first image to the value of item 0 in the photos array, which is the string images/Pears.jpg.
001 var img = document.getElementById("one");
002 img.src = photos[0];
10. Loading the code
In the previous tutorial we wrote the code in a <script> element in the body of the page, and that code ran as the browser loaded the HTML page. This time around, we’re going to include a JavaScript file from the <head> of the page. When doing this, a potential problem can occur when the browser begins evaluating JavaScript in the <head> element before it has read the rest of the page; this is because the DOM hasn’t fully been constructed.
11. Write a function
To fix this we need to ensure that the code isn’t executed until the rest of the page has been fully loaded. To do that you can place the code in a function, as detailed below:
001 function init() {
002 var img = document.getElementById("one");
003 img.src = photos[0];
004 }
Note that by defining a function, what you’re actually doing is packaging up this code so that you can reference it by the name init (see the boxout to the left for more on functions). Any time that you call init(), the code defined in its body (the code between the curly braces) is evaluated.
12. The window.onload property
So, how do you get your JavaScript to wait until the page is fully loaded before the init function is called? You use the window.onload property, which is available in every browser. If you assign the property to a function, then that function will be called once (and only once) the page has been fully loaded (and the DOM created), which is exactly what we want. Here’s how to set the window.onload property:
001 function init() {
002 var img = document.getElementById("one");
003 img.src = photos[0];
004 }
005 window.onload = init;
Make sure you type ‘init’, not ‘init()’, on line 5. Why? Because you aren’t calling this function, you’re leaving it up to the browser to call it once the page is loaded.
Try loading the page now, and you should see a photo appear in the browser window.
13. Add the descriptive text
At this point, you’ve got an image displayed, but what about the description? To display the description, we need to get the <div> element with the id ‘description’ from the DOM (line 4), and then set its content, using the innerHTML property, to the descriptive text in the descriptions array (line 5). Once you’ve added this code, reload the page and you should see the first photo with its descriptive text.
001 vfunction init() {
002 var img = document.getElementById("one");
003 img.src = photos[0];
004 var div = document.getElementById("description");
005 div.innerHTML = descriptions[0];
006 }
007 window.onload = init;
14. Keep track of your images
Add a new variable – photoIndex (line 1) – which will hold the next image/description we’re going to transition to. A good place to add this variable is underneath the two arrays we created earlier.
001 var photoIndex = 0;
15. Create a function for the transition
Now write a new function – transition – that will increase the value of photoIndex by 1 (line 4), to indicate the next image item in the array to display. You need to check to see if we’ve reached the end of the array; if we have, set photoIndex back to 0 so we start again at the beginning of the array the next time the function is called. Use a property of the array – the length property – to test to see if photoIndex is too big.
001 var photoIndex = 0;
002
003 function transition() {
004 photoIndex = photoIndex + 1;
005 if (photoIndex >= photos.length) {
006 photoIndex = 0;
007 }
008 }
16. Change the image sources
Now get the <img> elements from the DOM (lines 6-7). Remember that the <img> element with the id ‘one’ has the current image that is displayed. The next image is the image in the photos array at the index with the current value of photoIndex. Put this image in the <img> element with the id ‘two’ (line 8). The corresponding text for that image is the string at array index photoIndex in the descriptions array; put that text into the description <div> (lines 9-10).
001 function transition() {
002 photoIndex = photoIndex + 1;
003 if (photoIndex >= photos.length) {
004 photoIndex = 0;
005 }
006 var currentImg = document.getElementById("one");
007 var newImg = document.getElementById("two");
008 newImg.src = photos[photoIndex];
009 var div = document.getElementById("description");
010 div.innerHTML =descriptions[photoIndex];
011 }
17. Add the fade effect
When you add the class ‘transparent’ to an <img> element, it fires off a CSS transition that fades the image. We are transitioning from image one to image two, so you need to add the transparent class to image one and remove the class from image two. Use the setAttribute() function to add the transparent class to image one (line 11); this causes it to fade.
001 function transition() {
002 photoIndex = photoIndex + 1;
003 if (photoIndex >= photos.length) {
004 photoIndex = 0;
005 }
006 var currentImg = document.getElementById("one");
007 var newImg = document.getElementById("two");
008 newImg.src = photos[photoIndex];
009 var div = document.getElementById("description");
010 div.innerHTML =descriptions[photoIndex];
011 currentImg.setAttribute("class","transparent");
012 }
18. Remove the transparent class from the previous photo
Note that the setAttribute function takes two arguments: first the attribute to set, and second, the value of the attribute. We’ll use it now to remove the transparent class from image two by using an empty string for the value (line 12).
001 function transition() {
002 photoIndex = photoIndex + 1;
003 if (photoIndex >= photos.length) {
004 photoIndex = 0;
005 }
006 var currentImg = document.getElementById("one");
007 var newImg = document.getElementById("two");
008 newImg.src = photos[photoIndex];
009 var div = document.getElementById("description");
010 div.innerHTML =descriptions[photoIndex];
011 currentImg.setAttribute("class","transparent");
012 newImg.setAttribute("class", "");
013 }
19. Create arrays to hold image names and text
Now let’s transition between images when you click anywhere in the browser window. To do this, set the onclick property of the window to the transition function (line 14). This is similar to how you set the onload property of the window to init earlier. Once you’ve done this, if you click in the browser window, the transition() function will be called and the first image will fade and the next image from the array will appear.
001 function transition() {
002 photoIndex = photoIndex + 1;
003 if (photoIndex >= photos.length) {
004 photoIndex = 0;
005 }
006 var currentImg = document.getElementById("one");
007 var newImg = document.getElementById("two");
008 newImg.src = photos[photoIndex];
009 var div = document.getElementById("description");
010 div.innerHTML =descriptions[photoIndex];
011 currentImg.setAttribute("class","transparent");
012 newImg.setAttribute("class", "");
013 }
014 window.onclick = transition;
20. More than one transition
Right now the code only supports a transition from one image to a second. To keep transitioning images whenever you click on the browser window, you have to do a bit more work. To do this, we’ll use a new variable – current – to keep track of which image is currently visible. Add the new current variable to your JavaScript, under where you added photoIndex earlier, and initialise current to the value ‘one’, the id of the image that is visible when your app starts up (line 2).
001 var photoIndex = 0; 002 var current = "one";
21. Update the transition function
In the transition() function, when you get the currently visible image from the DOM and store it in the variable currentImg, instead of using the value one for the id, you’ll use the value in the variable current (line 6). The first time you call transition() this will be one, but the next time, it will be two, because after getting the currentImg, you’ll then switch current to two. But we can’t always just set it to two because if currentImg is currently two, we want to set it back to one. So, to overcome this, we’ll use an if test; if current equals one, we set it to two, otherwise (that is, current equals two) we set it to one (lines 7-11).
001 function transition() {
002 photoIndex = photoIndex + 1;
003 if (photoIndex >= photos.length) {
004 photoIndex = 0;
005 }
006 var currentImg = document.getElementById(current);
007 if (current == "one") {
008 current = "two";
009 } else {
010 current = "one";
011 }
012 var newImg = document.getElementById("two");
013 newImg.src = photos[photoIndex];
014 var div = document.getElementById("description");
015 div.innerHTML =descriptions[photoIndex];
016 currentImg.setAttribute("class","transparent");
017 newImg.setAttribute("class", "");
018 }
22. Finishing up the app
You also need to update where you set the value of newImage to use the new value of current (line 12). If currentImg is set to image one, and we switch current to two, then newImage should be set to image two (and likewise, if currentImg is set to image two, then newImage should be set to image one). Once you have made this change and you reload the page, you should now be able to transition between images every time that you click on the browser window.
001 function transition() {
002 photoIndex = photoIndex + 1;
003 if (photoIndex >= photos.length) {
004 photoIndex = 0;
005 }
006 var currentImg = document.getElementById(current);
007 if (current == "one") {
008 current = "two";
009 } else {
010 current = "one";
011 }
012 var newImg = document.
013getElementById(current);
014 newImg.src = photos[photoIndex];
015 var div = document.getElementById("description");
016 div.innerHTML =descriptions[photoIndex];
017 currentImg.setAttribute("class","transparent");
018 newImg.setAttribute("class", "");
019 }