Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / CSS

A D.I.Y. Lightbox

5.00/5 (2 votes)
7 Jul 2011CPOL3 min read 10.6K   188  
LiteBox is a very simple, lightweight jQuery lightbox, which can serve as an example for anyone wishing to develop their own solution; or as a base for anyone wishing to extend it further.

Introduction

OK, so JavaScript/jQuery lightboxes are ten-a-penny. Just go to the jQuery plugin repository and take your pick! Indeed for a long time, I did just that. After all, there's no point re-inventing the wheel, is there??

However, I recently had to write my own JavaScript lightbox from scratch. So I thought now was a good opportunity to share my experiences with you, as well as the code, which you are free to use should you want or need to develop your own lightbox or maybe want to develop my lightbox further.

LiteBox

The fruits of my labours I have (unimaginatively) named 'LiteBox', mainly to try and emphasize the fact that it makes no pretences to doing anything fancy! Also, as I am a shameless jQuery whore, I am also assuming prior experience of jQuery. If you are unfamiliar with jQuery, you can find more information here.

The Basics

LiteBox is implemented as a jQuery plugin. The signature is as follows:

JavaScript
jQuery.lightbox( url, [options] )

The url parameter is mandatory and specifies the URL of the image to be shown in the lightbox. The options parameter is a set of optional key/value pairs for configuring the lightbox:

KeyDescriptionDefault Value
titleThe text to be used for the tooltip and alt attribute of the image.The URL of the image
showCloseButtonWhether or not to show the 'close' button on the lightbox.True
closeButtonPositionThe position of the 'close' button.
Can be one of either 'top-left', 'top-right', 'bottom-left' or 'bottom-right'.
Ignored if showCloseButton is false.
'top-right'
animationSpeedThe speed of the animation.
Can be one of either 'slow', 'medium' or 'fast'; or the length of the animation in milliseconds.
'medium' (= 500ms)

Getting Into the Code

Before we delve too deeply into the JavaScript, it's helpful to have a look at the CSS:

CSS
.jquery-litebox-lightbox
{
 position: absolute;
 background-color: Transparent;
 z-index: 1001;
 margin: 0px;
 padding: 0px;
 border: 10px solid white;
}

.jquery-litebox-img
{
    margin: 0px;
    padding: 0px;
}

.jquery-litebox-close
{
    height: 25px;
    width: 25px;
    position: absolute;
    cursor: pointer;
    background-image: url(images/jquery-litebox_close.png);
    background-repeat: no-repeat;
    z-index: 1002;
}

.jquery-litebox-shadow
{
 position: absolute;
 top: 0;
 left: 0;
 width: 100%;
 height: 100%;
 background-image: url(images/jquery-litebox_shadow.png);
 background-repeat: repeat;
}

As is customary with jQuery plugins, the first thing we need to do is merge any user options into a settings object:

JavaScript
var settings = {
    title: url,
    showCloseButton: true,
    closeButtonPosition: 'top-right',
    animationSpeed: 'medium'
};
$.extend(settings, options);

The next thing to do is create a <img> tag for the full-sized image, and add it to the DOM. It is important that we do this early on as we need the browser to have loaded the image in order to work with its properties, such as height and width, etc. However, we make the image invisible so that it doesn't actually appear to the user yet:

JavaScript
var img = $('<img src="' + url + '" alt="' + settings.title +
'" title="' + settings.title + '" class="jquery-litebox-img" style="display: none;" />');
$('body').append(img);

Once the browser has loaded the image, then the interesting stuff can start. By hooking into the image's load event, we can create the lightbox and append the image to it:

JavaScript
var imgWidth = $(this).width();
var imgHeight = $(this).height();
$(this).detach().height('0px').width('0px');
var lightbox = $('<div class="jquery-litebox-lightbox"></div>').css
	('top', $(window).scrollTop() + 100 + 'px').css('left',
	($(window).width() / 2) - (imgWidth / 2) + 'px');
var shadow = $('<div class="jquery-litebox-shadow"></div>');
$('body').append(shadow);
$('body').append(lightbox);
lightbox.append($(this));

As you can see, we firstly get the height and width of the image. We then detach the image from the DOM and set its height and width to 0px.

Next, we create the lightbox itself. Now that we know the height and width of the image, we can calculate and set the position of the top-left-hand corner of the lightbox such that it will be centered horizontally on the page and 100px from the top of the window.

We then create the lightbox shadow and append it to the DOM. We append the lightbox itself to the DOM and then append the image to the lightbox.

Now the time has come to animate our lightbox. The animation is very simple: we simply grow the image from top-left to bottom-right until the image is at its full size. This is achieved using jQuery's animate() function:

JavaScript
var animationTime = getAnimationTime(settings.animationSpeed);
$(this).show().animate({
    width: imgWidth,
    height: imgHeight
}, animationTime, function () {
    if (settings.showCloseButton) {
        showCloseButton(settings.closeButtonPosition);
        img.mouseover(function () {
            showCloseButton(settings.closeButtonPosition);
        });
        img.mouseout(function (e) {
            hideCloseButton(e);
        });
    }
});

When the animation is complete, we hook into the mouseover and mouseout events of the image to show and hide the close button respectively. The code for showing and hiding the button is as follows:

JavaScript
function showCloseButton(position) {
    var img = $("img.jquery-litebox-img");
    var imgPositionY = img.offset().top;
    var imgPositionX = img.offset().left;
    var imgHeight = img.height();
    var imgWidth = img.width();
    if ($("div.jquery-litebox-close").length == 0) {
        var close = $('<div class="jquery-litebox-close"
	title="Close the lightbox." style="display: none;"></div>');
        $('body').append(close);
        switch (position) {
            case 'top-left':
                close.css('top', imgPositionY).css('left', imgPositionX);
                break;
            case 'top-right':
                close.css('top', imgPositionY).css('left',
			(imgPositionX + imgWidth) - close.width());
                break;
            case 'bottom-left':
                close.css('top', (imgPositionY + imgHeight) -
			close.height()).css('left', imgPositionX);
                break;
            case 'bottom-right':
                close.css('top', (imgPositionY + imgHeight) -
		close.height()).css('left', (imgPositionX + imgWidth) - close.width());
                break;
            default:
                throw new Error("Buttom position must be one of either:
		'top-left', 'top-right', 'bottom-left' or 'bottom-right'.");
        }
        close.click(function (e) {
            $(this).remove();
            closeLightBox();
        });
        close.show();
    }
}

function hideCloseButton(mouseEvent) {
    if (!isIn($("div.jquery-litebox-close"), mouseEvent))
        $("div.jquery-litebox-close").remove();
}

function isIn(obj, mouseEvent) {
    if (obj.length > 0) {
        var x = mouseEvent.pageX;
        var y = mouseEvent.pageY;
        var posX = obj.position().left;
        var posY = obj.position().top;
        var objX = obj.width();
        var objY = obj.height();
        return x > posX && x < posX + objX && y > posY && y < posY + objY;
    }
    else
        return false;
}

The animation time is determined by calling the getAnimationTime() function:

JavaScript
function getAnimationTime(speed) {
    if (typeof speed === 'string') {
        switch (speed) {
            case 'slow': return 1000;
            case 'medium': return 500;
            case 'fast': return 250;
            default:
                var parsedSpeed = parseInt(speed);
                if (!isNaN(parsedSpeed))
                    return parsedSpeed;
                else
                    throw new Error("Animation speed must be a
			number or one of: 'slow', 'medium' or 'fast'.");
        }
    }
    else if (typeof speed === 'number')
        return speed;
    else
        throw new Error("Animation speed must be a number
			or one of: 'slow', 'medium' or 'fast'.");
}

Summary

LiteBox is a very simple, lightweight jQuery lightbox, which can serve as an example for anyone wishing to develop their own solution; or as a base for anyone wishing to extend it further.

You can download the source code, along with a sample web page from here.

You can see a demo of LiteBox in action here.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)