Today we have a guest post by Andy Walpole sharing his experience from creating the Lightbox Ultra on Mozilla Demo Studio. Several years ago developer Lokesh Dhakar created the familiar Lightbox script with Prototype and It’s smooth animation and sleek aesthetics were an instant hit in the web design community and it was used on a multitude of different projects.

View Demos

There have been many imitations – Fancybox and Thickbox to name just two – but Lightbox still remains as the favoured way to present images to a user. This, primarily, is due to its 3d animation and background dimming which allows the user to view the image without any distraction. It’s a useful, timeless technique.

Since CSS animation first started to be used a few years ago, coders have enjoyed creating their own CSS-only Lightbox versions. Indeed, there is a real craze for CSS-only animation experimentation. This is something we should all welcome. In the near future CSS will completely take over from JavaScript on the presentation layer so using it now for this purpose is perceptive forward thinking.

Just recently I had a CSS project exhibited on the Mozilla Demo site called Lightbox Ultra. Its core is CSS3 – in particular 3d animation – but in the process of creating the demo I realised that JavaScript added important usability and design features.

This guide is not a line-by-line explanation of the code I have written for my Lightbox project. Going into such tiny detail will only confuse the reader. Instead, I’ll explain some of the key concepts behind creating a modern take on the popular Lightbox script. That way you can then use these ideas in your own coding projects.

CSS and Lightbox

Firstly, the HTML is as below:

lightbox one

I used definition lists but I could have as easily used unordered lists. Note how the HTML code block for each image is split into two different parts – one for the thumbnail and the other for the full sized image.

The full-sized image needs to be set to “display: none” so that the initial state for the viewer is one where only the thumbnail is visible:

lightbox two

The Lightbox approach is for the full-sized image to appear after user interaction with the thumbnail.

This is possible with JavaScript events. The small code block below changes the CSS to “display:block” when the user clicks on the thumbnail (Here I use the querySelector() method which only has partial cross-browser support):

var thumbnail = document.querySelector(".first-image img");
var fullSize = document.querySelector(".second-image img");

thumbnail.onclick = function () { = "block";


The closest we have to JavaScript events in CSS is the :target pseudo-class. I don’t know whose idea it was to introduce :target into the CSS3 spec, but its inclusion was a minor act of ingenuity.

Instead of a script event like above it is possible to use the following CSS:

.second-image dl:target {
    display: block;

:target works by using a fragment in the URL. The link in the thumbnail has the following fragment: “#block-1”. The ID for the full size image is block-1. Clicking on the link with the fragment then triggers the HTML with an ID that is exactly the same as long, of course, as you specify this in your style sheet.

Because it is so different to other CSS, :target may appear a little confusing at first. The best method to become familiar with it is by rolling your sleeves up and experimenting with this pseudo-class on your own code.

:target will become one of the most used CSS3 features in the future. The reason it has only had limited use so far is that it is not supported in Internet Explorer versions 8 and below. I’ll discuss workarounds in the next section.

The actual CSS keyframe animation is fairly straightforward:

/* animation for main image */
.second-image dl:target .animation {
    -moz-animation: image3D 2000ms cubic-bezier(0.950,0.050,0.795,0.035);
    -webkit-animation: image3D 2000ms cubic-bezier(0.950,0.050,0.795,0.035);
    -ms-animation: image3D 2000ms cubic-bezier(0.950,0.050,0.795,0.035);
    -o-animation: image3D 2000ms cubic-bezier(0.950,0.050,0.795,0.035);
    animation: image3D 2000ms cubic-bezier(0.950,0.050,0.795,0.035);

/* image3D is used on the main image */
@-moz-keyframes image3D {
    0% {
       -moz-transform: rotateY(90deg);

    100% {
       -moz-transform: rotateY(0deg);

@-webkit-keyframes image3D {
    0% {
       -webkit-transform: rotateY(90deg);

    100% {
       -webkit-transform: rotateY(0deg);

@-o-keyframes image3D {
    0% {
       -o-transform: rotateY(90deg);

    100% {
       -o-transform: rotateY(0deg)

@-ms-keyframes image3D {
    0% {
       -ms-transform: rotateY(90deg);

    100% {
       -ms-transform: rotateY(0deg);

@keyframes image3D {
    0% {
       transform: rotateY(90deg);

    100% {
       transform: rotateY(0deg);

I will not explain the code above in detail because this article isn’t a tutorial on CSS3 animation. For that I would advise you to read introductions written by Tim Van Damme, Louis Lazaris and Tom Waterhouse.

Note in the code above I used Webkit, Firefox, Microsoft and Opera prefixes. As of yet there is no keyframe support in Internet Explorer or Opera but it will be coming soon so it’s best to future-proof your code.

JavaScript and Lightbox

On my Mozilla Demo page I had a lot of fun creating a modern take of Lightbox with CSS3. I used box-shadows, the calc() function, gradients and CSS3 transforms. If you turn off JavaScript in your browser and try the demo out in a modern non-IE browser you will see it is in perfect working order.

However, there are are number of pitfalls with a CSS-only approach.

Firstly, CSS3 animation only fires once. This is an issue previously well documented by Oli Studholme and Chris Coyier.

CSS3 keyframes animation will only work again if the page is refreshed. One way around is to use transitions instead of keyframes. Another way is to use JavaScript to rebuild the node every time the animation is fired.

In the change_animation() method I remove the old class, clone the relevant part of the DOM, randomly add a new class, delete the online node and replace it with the DOM clone:

change_animation: function (htmlElement) {

    var items, random, regEx, result, key, mainBlock, cloneBlock, parentBlock;

    // below finds the unique key which is in the parent div id
    function removeArrayElement(element, index, array) {
       return (!;

    regEx = /.([0-9]+)$/;
    result = regEx.exec(htmlElement.parentNode);
    key = result.filter(removeArrayElement).toString();

    // this unique key is then used to find the large image in the overlay
    // this is an alternative to some bonkers DOM transversal method
    mainBlock = document.querySelector("#block-" + key + " img");

    // remove previous animation class
    mainBlock.removeAttribute("class", "");

    // In order for CSS animation to run more than once on the same element
    // It is necessary to rebuild the node
    // See for further details:
    cloneBlock = mainBlock.cloneNode(true);

    // select a class at random
    items = this.classes;
    random = items[Math.floor(Math.random() * items.length)];

    // rebuild the html adding the new class
    cloneBlock.setAttribute("class", random);

    parentBlock = mainBlock.parentNode;


I’m sure you could write less verbose code if you used jQuery.

What this means is the global object user interface is as below:

    // declare CSS classes that are used for animation
   classes: ['image3D', 'flipper', 'bulge', 'bouncing', 'side-spin', 'top-spin', 'shadow-play', 'rush']

In order to change the animation just add a new class to your CSS and to the JavaScript facade. Referenced above, “top-spin” CSS looks like this:


.top-spin {
    -moz-animation: topSpin 2000ms cubic-bezier(0.000, -0.600, 0.000, 1.650);
    -webkit-animation: topSpin 2000ms cubic-bezier(0.000, -0.600, 0.000, 1.650);
    -ms-animation: topSpin 2000ms cubic-bezier(0.000, -0.600, 0.000, 1.650);
    -o-animation: topSpin 2000ms cubic-bezier(0.000, -0.600, 0.000, 1.650);
    animation: topSpin 2000ms cubic-bezier(0.000, -0.600, 0.000, 1.650);

@-moz-keyframes topSpin {
    0% {
       -moz-transform: rotateX(0deg);
       -moz-transform-origin: 0% 50% 0;

    100% {
       -moz-transform: rotateX(360deg);
       -moz-transform-origin: 0% 50% 0;

@-webkit-keyframes topSpin {
    0% {
   opacity: 0.1;
       -webkit-transform: rotateX(0deg);
       -webkit-transform-origin: 0% 50% 0;

    100% {
   opacity: 1;
       -webkit-transform: rotateX(360deg);
       -webkit-transform-origin: 0% 50% 0;

@-o-keyframes topSpin {
    0% {
       -o-transform: rotateX(0deg);
       -o-transform-origin: 0% 50% 0;

    100% {
       -o-transform: rotateX(360deg);
       -o-transform-origin: 0% 50% 0;

@-ms-keyframes topSpin {
    0% {
       -ms-transform: rotateX(0deg);
       -ms-transform-origin: 0% 50% 0;

    100% {
       -ms-transform: rotateX(360deg);
       -ms-transform-origin: 0% 50% 0;

@keyframes topSpin {
    0% {
       transform: rotateX(0deg);
       transform-origin: 0% 50% 0;

    100% {
       transform: rotateX(360deg);
       transform-origin: 0% 50% 0;

The second issue facing a CSS3 Lightbox is the lack of support in Internet Explorer. Unfortunately, versions 8 and below do not recognise the :target pseudo-class.

One way around this is to use a polyfill such as Dean Edwards IE7.js or Keith Clarke’s Selectivizr (the latter has support for IE8 only).

As the Sizzle engine has full CSS3 support I presume as well that you can use jQuery or Dojo.

However, my aim for my demo was to create it fully independent of any other JavaScript library. This is a tough call.

If a browser does not recognise a CSS pseudo-class or pseudo-element it will parse out the entire block of code. That means it is not possible to change the CSS using the styleSheets object because the CSS block using :target is not there to alter.

My solution was to use the XMLHttpRequest API to save the stylesheets to memory, change :target to a class called ieTarget, remove the old style sheets and then add the new altered CSS to the head. The ieTarget is then dynamically added and removed from the HTML depending on a click event being fired on the thumbnail or full-size close link.

Admittedly, it is quite a drastic move and one that leaves open all sorts of potential bugs and issues.

Lastly, if you are going to use JavaScript for Lightbox then why not use the new Full-screen API. This was introduced into Webkit in 2011 and made its first appearance in Firefox at the beginning of 2012.

The API is relatively straightforward to implement. I did so in the following function:

full_page: function () {

    var img, x, docElm, l;

    img = document.querySelectorAll(".first-image img");

    for (x = 0, l = img.length; x < l; x += 1) {

       // call full screen when clicking on the thumbnail
       img[x].addEventListener("click", function (evt) {

           docElm = document.documentElement;

           if (docElm.requestFullScreen) {
           } else if (docElm.mozRequestFullScreen) {
           } else if (docElm.webkitRequestFullScreen) {

       }, false);

    } // end for loop


It is now possible to access the global object in the following interface, with the Full-screen API being switched on and off with a boolean value:

    // declare whether you want to use the Full-screen API
   fullscreen: false,
    // declare CSS classes that are used for animation
   classes: ['image3D', 'flipper', 'bulge', 'bouncing', 'side-spin', 'top-spin', 'shadow-play', 'rush']


You may well wonder if there is a need for a JavaScript fullback for a CSS-based Lightbox, then why not just a use a wholly JavaScript approach and cut out the CSS animation? That, of course, is your pejorative. But let us put the sign up for everybody to read: animation for web design will soon be exclusively done by CSS, not JavaScript. In anticipation of this it makes sense to familiarise yourself with CSS animation now.

Using JavaScript too also means you can gain access to some of the funky new APIs like Full-screen.

If you do use CSS 3d animation then do so with caution. I think it is important to use it subtly rather than creating some garish 360 plus flipping and twisting. To do so would put the animation at the centre of attention rather than the images that are being presented.

About Author

Andy Walpole is a London-based freelance coder. He is currently collaborating with others on a number of different projects including a WordPress plugin for affiliate marketing and a Twitter service for teenagers. You can find him hanging around Twitter most days: @andywalpole


May 28, 2012 at 12:18 am

Excelent !.
Tnkx for sharing !

May 28, 2012 at 4:31 am

Really nice!

Wahab Hussain
May 28, 2012 at 9:25 am

Seems like not working properly in Opera. Kindly check Thanks
On Firefox it looks good.

Andy Walpole
May 29, 2012 at 5:26 am

Wahab, it’s not going to work the same in Opera as Firefox because the Full-screen API is, so far, only available in Firefox and Webkit-based browsers.

May 28, 2012 at 9:56 am

Not working properly in latest versions of Chrome or Firefox. Didn’t have behaviors I would expect from a lightbox at all. Couldn’t navigate using the gallery at the bottom on my 768 height screen since only a bit of the thumbnail showed. Didn’t have the standard arrows that appear on hover over the image to move from one picture to another either. So basically, I couldn’t navigate at all.

Andy Walpole
May 29, 2012 at 5:30 am

It’s working fine in the latest versions of Firefox and Chrome

I’ve only tested it out on the desktop so it’s not optimized for mobile devices

No there is no navigation, yet, it’s a means of presenting single images

May 28, 2012 at 10:29 am

Pretty awesome tutorial, Thanks for sharing!

May 28, 2012 at 1:31 pm

Great tutorial, thanks for sharing!

May 28, 2012 at 8:11 pm

I recommend correcting “pejorative” to “prerogative” since they mean very different things :) there are also some other typos (including an it’s/its) so maybe you’d like to do a once-over. Thank you for the article.

Andy Walpole
May 30, 2012 at 8:10 am

Well spotted. Perhaps Nick can change that mistake

Dave Curtis
May 28, 2012 at 10:05 pm

This post is very informative. We also help in improving websites and we manage web designs, development and SEO. Easy Web Services

May 29, 2012 at 12:43 am

Thanks for giving tutorial based on css3 and javascript with detailed description including code. I read your post really i get some knowledge.

Chris Devlin
May 29, 2012 at 4:57 am

Its working nice in firefox. Thanks for this tutorial. I wanna work in other browsers. Hope it works.

Augusto Valerio
May 30, 2012 at 5:04 pm

Thanks!!! it works wonders, I’ve been looking for a modern lightbox like this! I will for sure implement!!

Aranzamendez Website Design
May 31, 2012 at 1:32 am

Well, it really works for me for any browsers, this tutorial is really a good idea for us web designers.. Thanks for sharing it..

Adam Zoa
May 31, 2012 at 6:15 am

Very informative post and i have implemented it also. It feels good to say that works for any browser. Thanks Andy.

Morgan Feeney
May 31, 2012 at 7:17 am

Awesome display of the capabilities that are available within CSS and Javascript. I would love to see a responsive version, well when I say see… I mean use ;)


May 31, 2012 at 2:43 pm

It doesn’t work properly in Firefox. And the inability to go through images with a mouse click or keyboard doesn’t make any sense.

May 31, 2012 at 5:37 pm

Good explanation about css

Crusty McCrusterson
Jun 2, 2012 at 7:46 am

Really over-designed. Just because you can do something, doesn’t mean you should. I would say that this actually enhances the worst aspects of lightboxes. Nice effort, but designers should think carefully before implementing something this over-done.

Jun 3, 2012 at 7:49 am

A good example for the implementation you have certainly packed a lot in.

Thanks for sharing!

Bharat Chowdary
Jun 4, 2012 at 11:40 pm

Thanks for this awesome tutorial, liked the CSS.

Jun 6, 2012 at 11:57 am

I can’t wait for CSS3 to be fully supported or until people stop using the older browsers. Great post!

Well, it was nice knowing Flash. Maybe it’ll be buried next to Silverlight so I can visit them at the same time…

Carl Samuelsson
Jun 7, 2012 at 7:18 am

Really great lightbox! Good to see that CSS3 is finally coming!

Jun 8, 2012 at 2:27 pm

or you could just use javascript/jquery and waste a lot less time and have it work in more devices than this css3 only method will. i wish we had a better “target” method that didn’t make the screen jump to that element, it’s just ugly that way.

Boss Web Design
Jun 11, 2012 at 6:54 am

css3 is new and I get that “it’s the way of the future” but I prefer backwards compatibility. Using methods only supported by new browsers seems like a bit of a waste if you plan to grow your site and make it very popular. Well, I guess it’s only a waste if conversions/sales matter to you – my personal opinion.

Jun 13, 2012 at 12:34 pm

Good Lightbox.

Jun 14, 2012 at 5:11 am

Maybe this is modern, but in my firefox they work very bad/slow, and does not meet the requirements of good lightboox – speed work and usefull :)

Jun 14, 2012 at 11:08 am

nice effects :) great job

panoramy 360
Jun 15, 2012 at 9:37 am

Many Thanks, good post!

Mohamed Alaa
Jun 16, 2012 at 6:07 pm

Thanks for the nice post :) this is great!

patent search
Jun 18, 2012 at 4:46 am

Really nice post shared by you. With the help of css3 we can make many creative things like button, menu as well as slider also. Also i would like to use this new things.

Ankit kumar
Jun 18, 2012 at 6:15 am

really nice and informative post thanks for sharing it. Keep up.

Converage Integrated Media Solution
Jun 21, 2012 at 3:52 am

nice effects :) great job. Many thankx buddy.

Converage Integrated Media Solution

Jun 22, 2012 at 7:20 pm

Shrink, Share & Get Paid!
Go To to get paid for your posted links!

Jun 26, 2012 at 7:33 am

Hello Andy,

I see this CSS3 light box and I hope this will work out for all developers. Now I will start trying to integrate in local and I will try to get live once it’s done. I got lucky to get this new light box with full screen mode.

Thank you once again for this nice post and I am awaiting for new articles soon.

Jun 29, 2012 at 2:02 am

Nice Article… I hope one day my blog ( also appears on the list…

Jul 5, 2012 at 4:57 am

Im searching for this! Thank you Andy!

8 Bassein
Jul 6, 2012 at 1:42 am

Nice effect! But I’m more worried about the browser compatibility issue.

Ascentia Media
Jul 6, 2012 at 1:43 am

Nice effect! This could be the next lightbox style effect. CSS3 is definitely taking it’s place.

html code generator
Jul 9, 2012 at 4:46 pm

I’m curious to find out what blog platform you are utilizing? I’m experiencing some minor security problems with my latest site and I’d like to find something more risk-free. Do you have any recommendations?

game art and design
Jul 9, 2012 at 10:22 pm

Do you think a case study regarding how games change the brian or stem cells
be a excellent case study?

Jul 12, 2012 at 10:44 am

I just love to use lightbox! It makes a simple site looks great!

Jul 20, 2012 at 1:04 pm

im loving and zhetenging it now.

web site tasarımı
Jul 22, 2012 at 8:02 pm

Very helpful. Thanks for sharing!

Jul 23, 2012 at 6:03 pm

Very good, thanks for the information

Thiet ke logo
Jul 23, 2012 at 11:05 pm

thank you for sharing this experience
very useful but currently do not support multiple firox

installing ceramic tile, tiles r us, ceramic tile installing, kitchen wall tiles, natual stone tiles, ceramic tile, cheap carpet tiles
Jul 31, 2012 at 10:18 am

Hello! I could have sworn I’ve visited this blog before but after going through a few of the articles I realized it’s new to me.
Regardless, I’m certainly pleased I stumbled upon it and I’ll be book-marking it
and checking back frequently!

Linux VPS
Aug 9, 2012 at 10:03 am

Thank you for sharing your knowledge. Pretty useful information indeed.

Aug 11, 2012 at 6:36 am

very nice info thanks.

Stop Nail Biting
Aug 13, 2012 at 10:23 pm

Really great, Well done for your ideas on the review %BLOG TITLE%, they happen to be quite effective.
I appreciated reading your write-up.

Aug 21, 2012 at 8:18 am

I constantly spent my half an hour to read this weblog’s articles or reviews every day along with a mug of coffee.

Villanueva propiedades
Aug 28, 2012 at 1:06 pm

What’s up everyone, it’s my first visit at this website, and piece of writing is really fruitful in support of me, keep up posting such articles.

Aug 30, 2012 at 2:55 am

Very helpful. Thanks for sharing!

Sep 5, 2012 at 12:11 am

i like this

Nov 28, 2012 at 1:17 am


Feb 1, 2013 at 7:49 pm

Great. Thank for sharing !

Laundary cleaning
May 26, 2013 at 9:58 am

Hi Andy !
This is a cool tutorial. It’s very impressive to read. I am happy that we can also get codes from here.

Abegail Louise Acosta
Nov 28, 2016 at 12:30 am

I definitely need to sort that! Working as a newbie in a professional website development company.

Post Comment or Questions

Your email address will not be published. Required fields are marked *