I'm Dudley Storey, the author of Pro CSS3 Animation. This is my blog, where I talk about web design and development with HTML, CSS and SVG. To receive more information, including news, updates, and tips, you should follow me on Twitter or add me on Google+.

my books

Pro CSS3 Animation book coverPro CSS3 Animation, Apress, 2013

my other blogs

Massive Head CanonMassive Head Canon: Intelligent discussion of movies, books, games, and technology.

my projects

The New DefaultsThe New Defaults — A Sass color keyword system for designers.

CSSslidyCSSslidy — an auto-generated #RWD image slider. 3.8K of JS, no JQuery.

A Modern HTML5 Lightbox in 12 Lines of JavaScript

With no framework dependencies

“Lightbox” effects have been an established UI pattern for a decade, but the vast majority of implementations have been framework-dependent. In previous articles I’ve shown how to create a Lightbox UI using only CSS, although that version lacked controls. By adding the <dialog> element and a dozen lines of vanilla JavaScript, we can recreate a traditional lightbox perfectly:

The Markup

<nav id="thumbs">
<a href="elephant.jpg"><img src="elephant-thumb.jpg" alt></a>
<a href="taj-mahal.jpg"><img src="taj-mahal-thumb.jpg" alt></a>
<a href="wise-man.jpg"><img src="wise-man-thumb.jpg" alt></a>
</nav>
<dialog id="cover">
<button id="closecover">Close</button>
<img src="" alt>
</dialog>

The linked images follow the pattern used in my previous “Accessible Image Gallery with Progressive JavaScript” article; the large image inside the <dialog> element is a placeholder that we’ll change later using JavaScript. (alt values have been left blank for the sake of brevity).

The CSS

@keyframes fadeToNearBlack{
to { background: rgba(0,0,0,0.9); }
}
@keyframes goBig { to { opacity: 1; } }
nav { display: flex; } 
nav a { display: block; flex: 1; } 
nav a img, dialog img { width: 100%; height: auto; }
dialog { position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); border: none; opacity: 0; }
dialog button { border: none; background: none; font-size: 1.2rem; }
dialog[open] {
animation: goBig 1s .4s forwards;
width: 70%; margin: auto;
max-width: 700px;
}
dialog[open]::backdrop { animation: fadeToNearBlack 1s forwards; }
.backdrop { animation: fadeToNearBlack 1s forwards; }
dialog img { width: 100%; height: auto; }

The animations will fade in the <dialog> element; the <nav> links are displayed using flexbox to divide them evenly across the page. When visible, the <dialog> element is positioned using a variation on one of the established methods of centering elements when the height of the parent (the <body>, in this case) is unknown. (Vendor prefixes have been dropped for the purpose of clarity).

The JavaScript

The script goes at the end of the document; other browsers will require an additional polyfill to support the <dialog> element.

function showImage(e) {
e.preventDefault();
coverimage.setAttribute("src", this.getAttribute("href"));
coverimage.setAttribute("alt", this.querySelector("img").getAttribute("alt"));
cover.showModal();
}
document.getElementById("closecover").onclick = function() {
coverimage.setAttribute("src", "");
cover.close();
}
var imglinks = document.getElementById("thumbs").getElementsByTagName('a'),
cover = document.getElementById("cover"),
coverimage = cover.getElementsByTagName("img")[0];
testdialog=document.createElement("dialog");
testdialog.setAttribute("open", "");
if (!testdialog.open) { dialogPolyfill.registerDialog(cover); }
for (var i=0; i<imglinks.length; i++) { imglinks[i].onclick = showImage; }

The script attaches a function to each of the links; when the user clicks on one, it sets the src attribute of the large image in the <dialog> element to the value of the link and shows the modal window; the elements animate due to the CSS we applied earlier. Clicking on the altered <button> element closes the modal. Because the thumbnail images are links, they are also progressive and accessible.

Conclusion & Improvements

There are a few things that could be better; obviously, being able to drop the polyfill once all browsers support the <dialog> element would be good, and the element itself could be animated like the version in my CSS-only example. Centering the element perfectly across different platforms could also be improved: right now, things move around a little more than I would like. I’ll leave that and further enhancements for a future article.

Photographs by Richard Kardhordó, licensed under Creative Commons Play with the code for this gallery on CodePen

This site helps millions of visitors while remaining ad-free. For less than the price of a cup of coffee, you can help pay for bandwidth and server costs while encouraging further articles.