How To Create A Valid Lightbox with CSS and JQuery

Andrew J. Nelson
Published: 20 July 2011

Introduction

This tutorial will teach you how to make a lightbox effect using CSS and just a touch of JQuery. This how to is not intended to provide cut and past code for a user to implement in their own site; rather it is intended to teach the user how to create a lightbox from scratch and understand the method.

This method has several important goals. First, any Javascript we use must be gracefully degrading (meaning that if a user does not have JS enabled, they can still access the content in a transparent manner). Second, the code we use must be standards compliant. Third, the code must be cross-browser compatible.

Required Materials and Prior Knowledge

This how to is written for a user who is moderately familiar with HTML, CSS, and Javascript. You do not have to be an expert web designer, but this is not intended for someone who is just starting out or relies on a CMS to put out a blag. This method utilizes the JQuery library. However, anyone sufficiently familiar with Javascript can adapt it to their needs without using JQuery.

Understanding This Lightbox Method

This method creates three nesting <div>s. The outermost <div> is the trigger; when it is clicked on it activates the effect. The second <div>, contained within the first, is the overlay, which creates the opaque effect which covers the screen. The third <div>, contained within the second, is the content which we want to display.

The second <div> is hidden from view before the user clicks on the first <div> because it has the CSS property display: none. This property is applied via a class. Because the second <div> contains the third <div>, it inherits the display property and is also hidden.

Screenshot: Downloading Adobe Flash Player

An example thumbnail for launching the lightbox.

So why not use the visibility: hidden property to hide the lightbox instead of display: none? Because an element hidden with the visibility property still occupies space in the rendering, which will affect the flow of your document.

When the user clicks on the first <div>, we use a JQuery function to toggle the hidden property on the second <div>. When that happens, the lightbox becomes visible, with the overlay occupying the entire browser window and the content centered in the overlay. The application of the class which sets the hidden property is truly toggled on click, meaning that each click on the outermost <div> either applies or removes the display: none property. Since the entire lightbox is contained within the outermost <div>, the user can click anywhere on the lightbox to close it once it has been opened.

For the purposes of this how to, the outermost <div> will have the class .lbTrigger. The middle, or second <div>, will have the class .lbOverlay. The third, or innermost <div> will have the class .lbContent. As well, the class which will apply the hidden attribute will, shockingly, be called .hidden

Gracefully Degrading The Lightbox

Since the lightbox is activated through a javascript onclick event handler, we need a way of providing the same content to a user who does not have JS enabled. We do this by having the content of .lbTrigger be a link to the lightbox content. Normally, an anchor tag's onclick event will override a javascript onclick event, so when the user clicks on the trigger element, the browser will navigate to the new content. However, we can use JQuery to prevent this default behavior. Thus, if the user has JS enabled, the link won't work and the lightbox will. However, if the user does not have JS enabled, the link works just fine. Its an elegant solution.

The CSS For The Lightbox

Lets first look at the CSS for the trigger <div>. These properties really only have to do with document flow, and are not relevant to the lightbox effect per se.

.lbTrigger { float: left; width: 100% }

Next, lets examine the CSS for the middle <div>. Height and width are set to 100% so that it will occupy the entirety of the space available to it. We set position to fixed (not absolute!) so that the space available is the whole of the browser window. Z-index is set to 100, which places it above the containing layer. Last, we use an opaque background image to create the layer effect.

The first point of emphasis is the position: fixed property. I saw a bunch of tutorials that use position: absolute. That would render the element at the top of the document. If the trigger element is far enough down the page that you have to scroll, the overlay element will be rendered above and out of site. By using position: fixed, the overlay will render across the entire browser window, regardless of scrolling.

The second point of emphasis is that I use a background image to create the opaque layer. Many other lightboxes (not all) set the background color to black and then define its opacity property at, say, 80%. However, using CSS to set opacity is not cross browser compatible, nor is it standards compliant if you use browser specific hacks to set it. While I would like to have the performance gains associated with rendering a background color versus a repeating image, those gains are not worth sacrificing standards compliance. Or worse yet using a browser-specific hack. Who else remembers the bad old days of browser wars?

.lbOverlay { height: 100%; width: 100%; position: fixed; top: 0px; left: 0px; z-index: 100; background-image: url("../images/overlay.png"); }

Last, here is the CSS for the content element. Position is set to relative so that it calculates against its fixed position parent element. By setting width to 50%, and then left position to 25%, we guarantee that the content div will be centered. You can do the same with height, but for my personal ascetics I like to set the position 15% from the window top. Last, by setting text-align to center, whatever image is in this <div> will be centered.

There are other ways of setting width and centering, and I am not dogmatic about it. This works for a general purpose lightbox whose content may be of varying width and height within reasonable bounds. If you are working with content where the images are of a fixed size, you can specify sizes and use a more elegant solution.

.lbContent { position: relative; top: 15%; left: 25%; width: 50%; text-align: center; } .hidden { display: none; }

You will see that the class .hidden has just one property. This is the class which will be toggled on and off of the .lbOverlay by the JQuery onclick event.

The Markup

The HTML is straightforward. The trigger contains the thumbnail image, which is also a link to the full size image. (Graceful degradation, remember?) Nested in the trigger is the overlay, and nested in the overlay is the content, and nested in the content is the full size image.

<div class='lbTrigger'> <a href='images/yourimage.png' title='Your Image'> <img src='images/yourimage_sm.png' alt='Your Image' /> </a> <div class='lbOverlay hidden'> <div class='lbContent'> <img src='images/yourimage.png' alt='Your Image' /> </div><!-- //lbContent --> </div><!-- //lbOverlay' --> </div><!-- //lbTrigger -->

The only thing to really notice is that <div class='lbOverlay hidden'> has both the "lbOverlay" class and the "hidden" class applied to it. The hidden class will be toggled off by the JQuery script.

The JQuery Javascript

This is a very light use of JS for this lightbox. It does only two things: reveals the lightbox or hides it based on an onclick event, and prevents the default behavior of the trigger link. The JQuery library is a wonderful tool for the toolbox, and allows developers to do all kinds of neato whizbang effects on their website, along with really practical things like form validation.

The first step, of course, is to have the library available. Download it and extract it into where ever you keep your scripts. Then add a script element which references it to your head element. For example:

<script type="text/javascript" src="scripts/jquery-1.4.3.js"></script>

Next we are going to write a function to toggle the .hidden class on the .lbOverlay div., as well as prevent the trigger link from its default behavior. I write my JS in a separate file and call it from the head element, which is how this is demonstrated. We'll call it lb-example.js. Here is the code that goes into that file.

var lightbox = function() { $('div.lbTrigger').click ( function() { $('div.lbOverlay', this).toggleClass('hidden'); } ); $('div.lbTrigger').click ( function(event) { event.preventDefault(); } ); };

Now that we have the function written, lets insert the script element in the head so that the document can use it. Make sure that it comes AFTER the JQuery reference.

<script type="text/javascript" src="scripts/jquery-1.4.3.js"></script> <script type="text/javascript" src="scripts/lb-example.js"></script>

Last, we have to call the function when the document is ready. Insert this code into your head, once again AFTER the other two script elements. It should look like this:

<script type="text/javascript" src="scripts/jquery-1.4.3.js"></script> <script type="text/javascript" src="scripts/lb-example.js"></script> <script> $(document).ready(function(){ lightbox(); }); </script>

So to summarize the javascript portion: the JQuery library enables the writing of a simple function that toggles the .hidden class on click and suppresses the default behavior of the trigger link. We add the library and our external JS page to our head, then a call to the function in the head element.

Why Not All CSS?

There are some all CSS lightboxes out there, and I think they are a great idea. However, they work by using the :hover pseudo class, which means that the lightbox is activated simply by the user moving the mouse over the trigger. In my opinion, this behavior upsets users. Hell, I know it upsets me. I want webpages to do things when I click, not when the cat moves my mouse over a picture. (This is why I didn't like suckerfish menus either.) Until browsers work well with the :active pseudo class to make this happen, using Javascript to fire the onclick event is the only reliable way.

Conclusion

The tux logo for WG.

Share this article on Google+ or your favorite social media. Thanks!

This turned into something of a marathon article, thanks for sticking with it. I hope it helps you to understand the lightbox process, even if you use a premade one.

Copyright © 2008 - 2013 Andrew Nelson under the GPL v3 License except where noted.
Please see the README file for full licensing disclosure and credits.