Highlight the active thumbnail in a slideshow

Hi,

Here’s the slideshow embed code:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Slideshow</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
#large {width:448px; height:336px; background:#000 url(http://lh5.googleusercontent.com/-ugFamEhbqPo/Thc6hoArbwI/AAAAAAAAABA/PFeHcJhR4Xw/s800/image1.jpg) no-repeat center;}
#thumbs {padding-top:12px; overflow:auto; white-space:nowrap; width:448px;}
img {padding:1px; width:80px; height:60px;}
img:hover {background:#00F;}
</style>
</head>
<body>
<div id="large"></div>
<div id="thumbs">
<img src="http://lh3.googleusercontent.com/-hUXeHq5OxEo/Thc7hFFv3gI/AAAAAAAAABQ/Yh7omR8iwzI/s800/thumb1.jpg" alt="" onclick="document.getElementById('large').style.backgroundImage='url(http://lh5.googleusercontent.com/-ugFamEhbqPo/Thc6hoArbwI/AAAAAAAAABA/PFeHcJhR4Xw/s800/image1.jpg)';">
<img src="http://lh3.googleusercontent.com/-JU5a-eDnOSg/Thc7g5UkwLI/AAAAAAAAABI/9aCyCMixWb4/s800/thumb2.jpg" alt="" onclick="document.getElementById('large').style.backgroundImage='url(http://lh3.googleusercontent.com/-u5BHGxpr0rg/Thc6hLbDRKI/AAAAAAAAAA8/IvQWzJBvqjg/s800/image2.jpg)';">
<img src="http://lh4.googleusercontent.com/-TdbbNGFbDNk/Thc7g0IBSsI/AAAAAAAAABM/pxpntZaTVoQ/s800/thumb3.jpg" alt="" onclick="document.getElementById('large').style.backgroundImage='url(http://lh4.googleusercontent.com/-4AMWSfi8q7A/Thc6haUv1QI/AAAAAAAAABE/oRdTWawPi_c/s800/image3.jpg)';">
</div>
</body>
</html>

I wonder how I can highlight the active thumbnail so its background remains blue until I click another one.
I also like to avoid the inline JavaScript. Any feedback to improve the coding is appreciated!

Best regards
Mike

You can set a class name to the img so that CSS can applied to that class. Typically you remove the class name from all of them, then add it to one of them.

Before you do that though, let’s remove the inline scripting and use a single set of code to achieve the same result.

The large image needs to be indicated somewhere, so linking to it from within an anchor tag is the standard way that sort of thing is done. Scripting can then take over the onclick event, make use of the image from the link, and then cancel the default behaviour of that link to prevent the web browser from following it.

Here’s how one of the linked images would look:


<a href="http://www.sitepoint.com/forums/javascript-15/.../image1.jpg"><img src="http://www.sitepoint.com/forums/javascript-15/.../thumb1.jpg" alt=""></a>

We should use scripting to set up the onclick behaviour. We want to put the script at the bottom of the body.


<html>
<head>
...
</head>
<body>
...
<script src="script.js"></script>
</body>
</html>

The end of the body is the best place to put scripts, because it speeds up the loading of your page, and you can easily work with elements on the page from the script.

We want to loop through each of the anchor links, and set up an onclick event for each link.


var thumbs = document.getElementById('thumbs'),
	links = thumbs.getElementsByTagName('a'),
    i;
for (i = 0; i < links.length; i += 1) {
    links[i].onclick = imageHandler;
}

The imageHandler function can access the link via the this keyword:


function imageHandler() {
    var large = document.getElementById('large');
	large.style.backgroundImage = 'url(' + this.href + ')';
	return false;
}

That now functions as a clickable slideshow, with the added benefit that extra functionality can be added on to things.

At the end of the imageHandler function, we can add on a call to another function that will deal with the class names.


function imageHandler() {
    ...
	setActiveLink(this);
	return false;
}

The setActiveLink will loop through all the links removing their class name, and then set a class name of “active” to one of them.


function setActiveLink(link) {
    var links = link.parentNode.getElementsByTagName('a'),
    i;
	for (i = 0; i < links.length; i += 1) {
		links[i].className = '';
	}
	link.className = 'active';
}

You can then use CSS to set the image background of the appropriate active one.


.active img {
    background:#00F;
}

Comprehensive and educational! Thank you! :slight_smile:

Dear Paul,

If we want to put the script on the head, is it correct coding:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html> 
<head> 
<title>Slideshow</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript">
function imageHandler() {
        document.getElementById('large').style.backgroundImage = 'url(' + this.href + ')';
        setActiveLink(this);
	return false;
}
function setActiveLink(link) {
var links = document.getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
        links[i].className = '';
	}
	link.className = 'active';
}
window.onload = function() {
var links = document.getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
        links[i].onclick = imageHandler;
}
}
</script>
<style type="text/css">
#large {width:448px; height:336px; background:#000 url(http://lh5.googleusercontent.com/-ugFamEhbqPo/Thc6hoArbwI/AAAAAAAAABA/PFeHcJhR4Xw/s800/image1.jpg) no-repeat center;}
#thumbs {padding-top:12px; overflow:auto; white-space:nowrap; width:448px;}
img {padding:1px; width:80px; height:60px; border:0;}
a:hover img, a.active img {background:#00F;}
</style>
</head> 
<body> 
<div id="large"></div>  
<div id="thumbs"> 
<a class="active" href="http://lh5.googleusercontent.com/-ugFamEhbqPo/Thc6hoArbwI/AAAAAAAAABA/PFeHcJhR4Xw/s800/image1.jpg"><img src="http://lh3.googleusercontent.com/-hUXeHq5OxEo/Thc7hFFv3gI/AAAAAAAAABQ/Yh7omR8iwzI/s800/thumb1.jpg" alt=""></a>
<a href="http://lh3.googleusercontent.com/-u5BHGxpr0rg/Thc6hLbDRKI/AAAAAAAAAA8/IvQWzJBvqjg/s800/image2.jpg"><img src="http://lh3.googleusercontent.com/-JU5a-eDnOSg/Thc7g5UkwLI/AAAAAAAAABI/9aCyCMixWb4/s800/thumb2.jpg" alt=""></a>
<a href="http://lh4.googleusercontent.com/-4AMWSfi8q7A/Thc6haUv1QI/AAAAAAAAABE/oRdTWawPi_c/s800/image3.jpg"><img src="http://lh4.googleusercontent.com/-TdbbNGFbDNk/Thc7g0IBSsI/AAAAAAAAABM/pxpntZaTVoQ/s800/thumb3.jpg" alt=""></a>
</div>
</body>
</html>

JavaScript over the past couple of years has moved to placing scripts at the bottom of the body, for a couple of reasons.

First, JavaScript blocks the loading of the page, so when scripting it anywhere before the end of the body, page loading stops completely until that script has loaded, been interpreted, and has finished being run by the interpreter. Placing scripts at the end of the body results in the page being seen sooner by people loading the page, which makes the page seem like it’s loading faster than it otherwise would with scripts being run from the head section.

Second, with scripts running from the end of the body, you don’t need to use the onload event to trigger and run scripts. Because the DOM above the script is already loaded, scripts at the end of the body have full access to all of the elements on the page, so scripts can work with page elements right away. This means that they don’t have to wait for all of the images and other assets to finish loading (as a result of the onload event) before they can start doing their job. This results in the scripts running much sooner than they otherwise would from an onload event, which once again gives a performance improvement to what the user experiences.

Third, when you want to add other scripts to the page, your onload event is in danger of being clobbered by other scripts that load after it, that may want to use the onload event too. By putting scripts at the end of the body without needing to use any such onload events, your script is capable of running without interference from such issues.

So yes, while can be correct coding to use an onload event from the head section:


<html>
<head>
<script type="text/javascript" src="script.js"></script>
</head>
<body>
...
</body>
</html>

[highlight==“javascript”]
window.onload = function() {
var links = document.getElementsByTagName(‘a’);

};



There is a much greater benefit in terms of performance and reliability, by running the script directly from the end of the body:


```html4strict

&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
...
&lt;script type="text/javascript" src="script.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

[highlight==“javascript”]
var links = document.getElementsByTagName(‘a’);

Makes perfect sense! From now on I try to practice putting the scripts at the bottom of the body.

I really appreciate your time and detailed explanations! :slight_smile: