A few years ago I wrote a blog article titled Lightbox Can Bite Me. I’ve since removed that post, replacing it with this new and improved Lightbox in CSS3 technique: the code has changed, but my frustration with the original plugin has only deepened.
Everyone on the web is familiar with the Lightbox effect: one of the first popular JavaScript gallery plugins, variations on the idea quickly became ubiquitous. My frustration stemmed from that very ubiquity: many of my students use a Lightbox clone for their portfolios, but few ever bother to customize anything about the plugin. This lack of imagination becomes especially apparent when 20 of them show their portfolios at the same time during showcase.
It’s my hope that recreating Lightbox in the simpler syntax of CSS3 will lead to more people customizing the effect for their own sites with more variability and creativity.
Before I begin, I should point out that this code has three small drawbacks:
First, it is best suited for relatively short pages, as the vertical position of the large image is based on the height of the content, not the dimensions of the browser window. Pages that extend past the bottom of the browser window will drive the large images down when they are displayed.
Second, it uses a fairly advanced CSS model for vertically centering the content – flexbox – which is only supported in recent browsers. I’ll explain the flexbox layout module in depth in an upcoming article. Right now, Firefox’s implementation of flexbox is slightly quirky, so you’ll find that the example currently runs best in Chrome.
Finally, for the purpose of simplicity all of the images used in the example (by Kenny Louie, BriYYZ and Laszlo Ilyes, licensed under Creative Commons and used with permission) are all the same size; it’s completely possible to use images of different aspect ratios, at the cost of more code.
I’ve covered many of the techniques I use here in previous articles: the markup is simply an evolved version of the very first simple CSS gallery I ever wrote about, while the :target selector has been covered for use in tab-based navigation and imagemaps.
The HTML is fairly simple:
- <body id=core>
- <dl id=gallery>
- <dt>
- <a href=#pic1>
- <img src=false-creek-small.jpeg alt="False Creek, Vancouver, British Columbia">
- </a>
- <dd id=pic1>
- <a href=#core>
- <img src=false-creek.jpeg alt="False Creek, Vancouver, British Columbia">
- </a>
- <dt>
- <a href=#pic2>
- <img src=lake-louise-small.jpeg alt="Lake Louise, Alberta, Canada">
- </a>
- <dd id=pic2>
- <a href=#core>
- <img src=lake-louise.jpeg alt="Lake Louise, Alberta, Canada">
- </a>
- <dt>
- <a href=#pic3>
- <img src=wheat-field-small.jpeg alt="Wheatfield, Saskatchewan, Canada">
- </a>
- <dd id=pic3>
- <a href=#core>
- <img src=wheat-field.jpeg alt="Wheatfield, Saskatchewan, Canada">
- </a>
- </dl>
- </body>
The difference between this markup and the original simple CSS gallery is its use of id attributes and links. Each <dd> element has an id, and inside each associated <dt> element is a link to that id. Finally, each large image is linked back to the id on the <body> element. These linked id’s are used to initiate and close the animation for the large gallery images.
The base CSS:
- html { min-height: 100%; position: relative; }
- body { margin: 0; height: 100%; }
- dl { float: left; }
- dd a { background: #fff; display: block; transition: 4s box-shadow ease-in; }
- dt { margin-left: 1.2rem; width: 150px; margin-top: 1.2rem; }
- dt img { width: 150px; height: 150px; }
- dd img { width: 640px; height: 427px; }
- dd { margin-left: 0; background: rgba(0,0,0,0);
- position: absolute; top: 0; bottom: 0;
- width: 100%; height: 100%;
- display: box;
- box-pack:center;
- box-align:center;
- visibility: hidden; }
Not all this code is going to visibly affect our gallery yet. The interesting part is the position:relative on the <html> tag, which is required to correctly position our <dd> elements, which contain the large image versions. Those dd’s are placed in the top left corner of the browser window, and extend its full width, with the height decided by the content of the page. (If no content goes past the bottom edge, the height of the <dd> element is the height of the browser window).
The other unusual part is the use of flexbox to vertically center the image, necessary because (a) centering content in a web page has always been a royal pain and (b) We can’t know the size of the outer container (the browser window), at least until the vh unit is supported in CSS, eliminating most other traditional methods of vertically centering content.
The development of flexbox has, quite frankly, been a bit of a mess, going through iterations that have changed the syntax twice. Like the rest of the CSS3 code used in this example, flexbox code will require vendor prefixes: to show just how complex achieving backwards support for the module is, here’s just the Webkit prefixed versions and the various iterations of the standard:
- display: -webkit-box;
- display: -webkit-flexbox;
- display: box;
- display: flexbox;
- -webkit-box-pack:center;
- -webkit-box-align:center;
- -webkit-flex-pack:center;
- -webkit-flex-align:center;
- flex-pack: center;
- flex-align: center;
- box-pack: center;
- box-align: center;
Nasty stuff, right? Flexbox is a complex but very powerful layout system, which I’ll explain in greater depth in another article, now that it has finally settled down to a single spec. All you need to know for the purpose of this example is that the code centers our large image on the page in Webkit.
Next, the CSS for the presentation of the large version of the images:
- @keyframes photopresent {
- 0% { width: 0; height: 0; opacity: 0; }
- 30% { width: 640px; height: 0; opacity: 0; }
- 60% { width: 640px; height: 427px; opacity: 0; margin: 20px; }
- 100% { width: 640px; height: 427px; opacity: 1; margin: 20px; }
- }
- dd:target {
- visibility: visible; background: rgba(0,0,0,0.75);
- transition: 1.5s background linear;
- }
- dd:target a { box-shadow: 0 0 8px 8px rgba(0,0,0,0.35); }
- dd:target a img { animation: photopresent 3s forwards; }
Clicking on the thumbnail image will fade the body and bring in the associated large image in the sequence long-associated with the Lightbox JavaScript plugin. You can see the complete results on this separate page I made for the effect.
Because :target places the id in the URL, following links such as this one will animate the associated large image in the gallery, which is really useful for highlighting pieces in a portfolio to a client.
Naturally it is possible to take this a lot further: adding code and content to allow captions to appear on rollover, reversing the animation when the large image is clicked rather than having it disappear, etc. There are many design options: it is my hope that this humble beginning might inspire you to start exploring the possibilities.

Haha, that is actually incredibly clever.
![Prometheus: Collector's Edition (Bilingual) [Blu-ray 3D + Blu-ray + DVD + Digital Copy] Prometheus: Collector's Edition (Bilingual) [Blu-ray 3D + Blu-ray + DVD + Digital Copy]](http://ecx.images-amazon.com/images/I/5192I1rtYnL._SL160_.jpg)

