AJAX Powered Lightbox

You may or may not have heard about “Lightbox”. This script is well known for creating the effect of dimming out a page and showing an element (like a picture or page) in the foreground at full illumination. Against the dark background this makes the element pop as well as disables the background temporarily for the user. The effect is nice for things like photo galleries or showing text snippets. The idea here will be to keep things minimal and only what you need to pull it off. I will show you how you can go about creating your own version of this script to play around with on this episode of the Programming Underground!

Lightbox has been around for awhile and has even spawned off scripts like Thickbox and Thinbox. Its primary use is for showing pictures in a gallery style fashion, but can theoretically be used to return any kind of data from pictures to full web pages to a mix of pictures and text. You can see a screenshot of this effect on the Wikipedia page for Lightbox at Lightbox – Wikipedia.

Over time it has been refined, and functionality added, for all sorts of actions and animations. But what if you don’t want to download some framework or don’t need all the extra features? Well you are in luck, you can create the basic idea with a few pieces of code.

So essentially we need four things to get our creation up and running…

1) Standard HTML to create our div overlay or “view pane” as we will call it. This is just a few simple div tags. These tags will be used to take whatever data coming in and display it to the user.

2) Javascript to show and hide the viewer (aka toggle the viewer pane’s visibility)

3) Ajax – Some very basic AJAX functionality to send our requests to an external page (hosted on our server though, I will explain that in a minute) and takes in the information received without needing to reload the page.

4) Cascading StyleSheets (CSS) – Style the viewer background and the viewer pane to give us the transparent and “lighting” effect for our div overlay.

First thing we are going to do is put some hidden div tags on our target page. One div called “previewback” will be the transparent backing of the Lightbox overlay. We will make it black and transparent through the CSS. The other div is going to serve as the articleviewer which will contain a viewerpane div (to show the content) and any other stuff we want to show in the viewer… like a close button.

This is how they will look…

<!-- This is simply the transparent back div that takes up the screen -->
<div id="previewback" style="display: none;">

</div>
	
<!-- Our article viewer, along with previewback, is hidden. It is the content pane that is loaded with content 
	   we get from other sources. It is the view window and since we set overflow-x and overflow-y it will have
	   scrollbars -->
		
<div id="articleviewer" style="display: none;">
	 <div id="viewerpane">
		  One moment please...
	 </div><br/>
		
	 <!-- Closes our viewer window -->
	 <input type="button" value="Close Viewer" onclick="hideViewer()"/>
</div>

You will notice that the viewerpane has some content already. We put the “One moment please…” message there so that as we are fetching the content to put in the pane, the user knows that something is coming. Since we are going to use asynchronous calls through our AJAX, the response may come in at any time from “instantly” to 5 seconds to maybe never. This message will give the user an idea that something may be coming in a moment.

We also have a simple button on the viewer which is used to call a JavaScript function to close the viewer. The JavaScript to show and the hide the viewer is like so…

// Toggle lightbox viewer
function toggleViewer(onoff) {
	var viewerback = document.getElementById("previewback");
	var viewer = document.getElementById("articleviewer");
	
	if (onoff) {
		viewerback.style.display = "block";
		viewer.style.display = "block";
	}
	else {
		viewerback.style.display = "none";
		viewer.style.display = "none";
	}
}

// Request the page through AJAX and when ready, it will launch the viewer
function launchViewer() {
	getData("a_page_on_your_server.html", "viewerpane");
	toggleViewer(true);
}

This toggleViewer() function essentially toggles the display of the divs we put on the page. The launchViewer() function is going to be our controlling function which will make a request to our AJAX functions (shown below) and opens up the viewer. Here we are requesting an HTML page on our server and telling it to load its source into the object called “viewerpane”.

The getData() function is our AJAX function that uses an XMLHttpRequest object to go out and get us the page for us. While we use a static page call in the code above, ideally you will want launchViewer to take in a parameter that it can pass on to getData. In addition to that, whatever you request will then be placed into our viewerpane div. It will be shown using the call to toggleViewer().

One thing you have to be aware of when using the AJAX code is that Firefox has taken the liberty of preventing AJAX calls to web pages from other domains. This is a security issue that was put in place so that pages can’t fetch harmful downloads from other sites and put it into people’s pages and onto visitors computers. This is why you must host the pages you are fetching on our own server through the same domain where this page is being hosted.

If you do try and attempt to fetch a page from another site, like Google.com for instance, then you will see Firefox spit back an error like “Access to restricted URI denied” in the Error Console. This shouldn’t be an issue if you host the graphics for your gallery on your own web host or fetch pages that reside on your own server. However, keep this in mind in case you are trying to read data streams from an external website.

One way you could get around this I am sure is by creating a server-side page (in ASP or PHP) which reads the external content from another site and shows the content to your Lightbox AJAX script. Since the AJAX script will see it coming from a page on your own server it won’t have a problem, but that page will be getting its content from somewhere else. This is essentially making the ASP/PHP script a proxy. I haven’t tried it myself but I am quite sure it will work fine.

Here is what our AJAX code looks like…

// AJAX code for fetching Lightbox content
var XMLRequestPost = false;
var XMLRequestGet = false;

// Get an XMLHttpRequest object for our AJAX
function getObject() {
	var XMLRequestObject = false;

	if (window.XMLHttpRequest) {
		XMLRequestObject = new XMLHttpRequest();
	}
	else if (window.ActiveXObject) {
		XMLRequestObject = new ActiveXObject("Microsoft.XMLHTTP");
	}
	return XMLRequestObject;
}


// This function is in charge of going to a URL, receive its response,
// and placing it inside the target object we have on the page. 
// In our case, the viewerpane.

function getData(sourcestring, targetobj) {
	  XMLRequestGet = getObject();
	var targetObject = document.getElementById(targetobj);
	  
	  if ((XMLRequestGet) && (targetObject)) {
		  
		  XMLRequestGet.open("GET",sourcestring);	
		
		// Once we receive the response, make sure it is ok and then set it in the target object
		// This is asynchronous, so it may take a minute or two to recieve a response.
		  XMLRequestGet.onreadystatechange = function() {
			  
			  if ((XMLRequestGet.readyState == 4) && (XMLRequestGet.status == 200)) {
				  targetObject.innerHTML = XMLRequestGet.responseText;
			  }
		  }
		  
		// Send the request
		  XMLRequestGet.send(null);
	  }
}

This code above is our functionality for getting a XMLHttpRequest object and using it to fetch a page. Now this isn’t the most comprehensive or bulletproof version of AJAX code, but for a simple send and request feature it will work for most users on most modern browsers. Notice how we take in our sourcestring (the page we are requesting) and uses it in a GET method to request the page. Once the response comes back, the onreadystatechange function we wired up here will execute and if all is ok (the status is 200 and ready) then we take the responseText and dump it into the object we specified to show output. For more information on how this all works, you can look up tutorials on AJAX.

In our example the targetObject is going to be a reference to our viewerpane div tag. The responseText is then dumped into that div tag for viewing. Keep in mind that this will only dump the HTML text but may not pull in things like CSS stylesheets etc for that page. Take appropriate precautions in handling that issue if you wish to use this like some kind of web browser.

Now that we have the div tags on our page, the JavaScript to toggle our viewer’s display on and off and our AJAX to get our page and put it into the viewer, the last thing left is some CSS to customize the viewer’s background the viewing pane.

#previewback {
	 width: 100%;
	 height: 100%;
	 background-color: #000000;
	 overflow: hidden;
	 margin: 0;
	 padding: 0;
	 opacity:.65;
	 filter: alpha(opacity=65); 
	 -moz-opacity: 0.65;
	 position: fixed;
	 left: 0;
	 top: 0;
	 z-index: 1;
}

#articleviewer {
	 z-index: 20;
	 position: fixed;
	 left: 0;
	 top: 0;
	 width: 100%;
	 height: 100%;
	 text-align: center;
}

#viewerpane {
	 margin: 20px auto;
	 overflow:auto; 
	 width:550px; 
	 height: 480px; 
	 background-color: #FFFFFF;
	 padding: 10px;
	 overflow-x:scroll;
	 overflow-y:scroll;
}

This styling is for personal tastes and you can alter many of the definitions here to give the viewer a different look and some different functionality. You can adjust the width and height of the viewer panel, change the color of the background, take out scrollbars if you want and change margins. I have created the top items to fit a screen running 1024 x 768 on both FF and IE.

One last thing I wanted to point out about this CSS is the use of z-index to make sure that both our previewback sits on top of the rest of the page and then our viewerpane sits on top of that. Make sure you keep the proper layer order or else you may see your viewerpane disappear or the previewback element not showing up correctly.

To put all these pieces together we can get an example page like so…

<html>
<head>
<title>Out LightBox Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript">

// Toggle lightbox viewer
function toggleViewer(onoff) {
	var viewerback = document.getElementById("previewback");
	var viewer = document.getElementById("articleviewer");
	
	if (onoff) {
		viewerback.style.display = "block";
		viewer.style.display = "block";
	}
	else {
		viewerback.style.display = "none";
		viewer.style.display = "none";
	}
}


// Ajax code for fetching Lightbox content
var XMLRequestPost = false;
var XMLRequestGet = false;

// Get an XMLHttpRequest object for our AJAX
function getObject() {
	var XMLRequestObject = false;

	if (window.XMLHttpRequest) {
		XMLRequestObject = new XMLHttpRequest();
	}
	else if (window.ActiveXObject) {
		XMLRequestObject = new ActiveXObject("Microsoft.XMLHTTP");
	}
	return XMLRequestObject;
}


// This function is in charge of going to a URL, receive its response,
// and placing it inside the target object we have on the page. 
// In our case, the viewerpane.

function getData(sourcestring, targetobj) {
	  XMLRequestGet = getObject();
	var targetObject = document.getElementById(targetobj);
	  
	  if ((XMLRequestGet) && (targetObject)) {
		  
		  XMLRequestGet.open("GET",sourcestring);	
		
		// Once we receive the response, make sure it is ok and then set it in the target object
		// This is asynchronous, so it may take a minute or two to recieve a response.
		  XMLRequestGet.onreadystatechange = function() {
			  
			  if ((XMLRequestGet.readyState == 4) && (XMLRequestGet.status == 200)) {
				  targetObject.innerHTML = XMLRequestGet.responseText;
			  }
		  }
		  
		// Send the request
		  XMLRequestGet.send(null);
	  }
 }
 
// Request the page through AJAX and when ready, it will launch the viewer
function launchViewer() {
	getData("a_page_on_your_server.html", "viewerpane");
	toggleViewer(true);
}	
</script>

<style>
	#previewback {
		width: 100%;
		height: 100%;
		background-color: #000000;
		overflow: hidden;
		margin: 0;
		padding: 0;
		opacity:.65;
		filter: alpha(opacity=65); 
		-moz-opacity: 0.65;
		position: fixed;
		left: 0;
		top: 0;
		z-index: 1;
	}

	#articleviewer {
		z-index: 20;
		position: fixed;
		left: 0;
		top: 0;
		width: 100%;
		height: 100%;
		text-align: center;
	}

	#viewerpane {
		margin: 20px auto;
		overflow:auto; 
		width:550px; 
		height: 480px; 
		background-color: #FFFFFF;
		padding: 10px;
		overflow-x:scroll;
		overflow-y:scroll;
	}
</style>
</head>

<body>

	<!-- Our link triggers the launching of the viewer -->
	Click <a href="java script:void(0)" onclick="launchViewer()">this link</a> to activate the viewer.<br/>
	This should then appear in the background.
	
	<!-- This is simply the transparent back div that takes up the screen -->
	<div id="previewback" style="display: none;">
		 
	</div>
	
	<!-- Our article viewer, along with previewback, is hidden. It is the content pane that is loaded with content 
		 we get from other sources. It is the view window and since we set overflow-x and overflow-y it will have
		scrollbars -->
		
	<div id="articleviewer" style="display: none;">
		<div id="viewerpane">
			One moment please...
		</div><br/>
		
		<!-- Closes our viewer window -->
		<input type="button" value="Close Viewer" onclick="toggleViewer(false)"/>
	</div>
	
</body>
</html>

This code can serve as a basic foundation for your own version of Lightbox and perhaps serve you in other ways. You could also part it out for different things like how to make div overlays, use the AJAX piece to make other applications or use the toggle code for toggling elements on a page.

As with all code on the Programming Underground, this is open to the public domain and you can do what you wish with it. Enjoy and I hope you had fun reading another issue of the underground. Now go out and enjoy the weather. 😉

About The Author

Martyr2 is the founder of the Coders Lexicon and author of the new ebooks "The Programmers Idea Book" and "Diagnosing the Problem" . He has been a programmer for over 20 years. He works for a hot application development company in Vancouver Canada which service some of the biggest tech companies in the world. He has won numerous awards for his mentoring in software development and contributes regularly to several communities around the web. He is an expert in numerous languages including .NET, PHP, C/C++, Java and more.