Some months ago, through a long-forgotten source, I came across this technique for fading in images without using flash and I’ve been looking for an excuse to play around with such techniques. Today, work on a new page for Calvin gave me such an excuse.
I wanted to use the technique within a javascript image gallery. I needed to be able to advance through a set of images and wanted to fade each in in turn. Since the images were named numerically, all it appeared to involve was a couple of javascript functions to increment or decrement a counter and update the photo accordingly. Because I’d be using the same image tag for all the images, I also tweaked the original’s functions to use a predefined object rather than making use of the DOM each time.
It all worked splendidly on my local server, but uploading to a test server I realised that I’d need to preload the images if I wanted to avoid flickering. I added in calls to check whether the next image had been previously loaded, and if not preload it into an array, and the flickering disappeared.
The resulting code is:
/* counter keeps track of which image we're displaying */
var counter;
/* display will be the pointer to the image object we're
* working with
*/
var display;
/* totalimages is the number of images we're displaying, so we can reset
* counter if necessary
*/
var totalimages = 9;
/*
* pics will hold our pre-loaded images
*/
var pics = new Array();
/* This function is called by the onload attribute of the
* body tag
*/
function initPage()
{
container = document.getElementById('display');
display = document.getElementById('display_image');
counter = 1;
pics[1] = new Image();
pics[1].src = 'slideshow/1.jpg';
pics[2] = new Image();
pics[2].src = 'slideshow/2.jpg';
pics[totalimages] = new Image();
pics[totalimages].src = 'slideshow/'+totalimages+'.jpg';
}
function advance()
{
if (counter == totalimages) {
counter = 1;
nextcounter = 2;
} else if (counter == totalimages - 1) {
counter++
nexcounter = 1;
} else {
counter++;
nextcounter = counter + 1;
}
setOpacity(0);
display.src = 'slideshow/'+counter+'.jpg';
if (! pics[nextcounter]) {
pics[nextcounter] = new Image();
pics[nextcounter].src = 'slideshow/'+nextcounter+'.jpg';
}
fadeIn(0);
}
function retreat()
{
if (counter == 1) {
counter = totalimages;
nextcounter = counter - 1;
} else if (counter == 2) {
counter--;
nextcounter = totalimages;
} else {
counter--;
nextcounter = counter - 1;
}
setOpacity(0);
display.src = 'slideshow/'+counter+'.jpg';
if (! pics[nextcounter]) {
pics[nextcounter] = new Image();
pics[nextcounter].src = 'slideshow/'+nextcounter+'.jpg';
}
fadeIn(0);
}
/* Altered from the original to use the global 'display'
* object
*/
function setOpacity(opacity)
{
opacity = (opacity == 100)?99.999:opacity;
// IE/Win
display.style.filter = "alpha(opacity:"+opacity+")";
// Safari<1.2, Konqueror
display.style.KHTMLOpacity = opacity/100;
// Older Mozilla and Firefox
display.style.MozOpacity = opacity/100;
// Safari 1.2, newer Firefox and Mozilla, CSS3
display.style.opacity = opacity/100;
}
/* Altered from the original to use the global 'display'
* object
*/
function fadeIn(opacity)
{
if (opacity < = 100)
{
setOpacity(opacity);
opacity += 10;
window.setTimeout("fadeIn("+opacity+")", 100);
}
}
Since it will eventually load all the images into an array, this may not be a good technique to use with large galleries. But for a small one, such as that I was working with there isn’t much to worry about.
UPDATE: I’ve refined this method further and written about it here.