Featherweight CSS3 Lightbox Gallery & No JS "AJAX"

Featherweight CSS3 Lightbox Gallery with No JS "AJAX"

Aug 24, 2015

Working with the "Mini Gallery" field type in Content Blocks for MODX CMS, I've come across the need a few times for an unobtrusive lightbox implementation. After Googling for "CSS only lightbox" I found this post and have been fiddling around with it since.

Below is my interpretation of it, which I've refined to meet the following criteria:

  1. Must meet the original criteria of being wholly CSS-based, requiring no Javascript whatsoever.
  2. Must meet basic "lightbox" functionality of thumbnails that, on click, display a larger image in an overlay or "modal".
  3. The large version of the image should be centered and contained within the viewport, surrounded by a translucent mask.
  4. Framework agnostic—must be compatible with Foundation, Bootstrap, or no framework at all.
  5. If at all possible, should only load the larger images on the thumbnail click action, rather than on page load.
  6. Must be as miniscule as possible.

Pagination controls were purposely left out, because it seemed to me the above requirements were hard enough to achieve without any JS at all, especially the "AJAXy" bit, which the post mentioned above didn't handle. Luckily, I found this useful tidbit of info about the way browsers deal with images WRT media queries—the tests on hidden elements being the most relevant here.

Full working demo here. See code comments therein for more info.

Here's a fragment of the HTML:

<ul>
    <li id="mgimg-1" class="mini-gallery-item">
        <div class="hider">
            <a  href="demos/no-js-css-only-lightbox/#_" 
                class="close-img"
                style="background: url(/blog-files/QE-Post/QE-Theatre-01.jpg) no-repeat center center rgba(0,0,0,.85);">
            </a>
        </div>
        <a href="demos/no-js-css-only-lightbox/#mgimg-1">
            <img src="/assets/components/phpthumbof/cache/QE-Theatre-01.fbeaccd35ff65222c9d2af990a0e8034.jpg" alt="Nice alt text for image 1">
        </a>
    </li>
    <!-- more items here -->
</ul>

This is the CSS:

.mini-gallery-item {
    list-style: none;
}
.mini-gallery-item .hider {
    display: none;
}
.mini-gallery-item:target .hider {
    display: block;
}
.mini-gallery-item:target .close-img {
    background-size: contain !important;
    z-index: 1;
    position: fixed;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
}

Break it down:

  1. The .hider container is required to prevent download of the hidden a.close-img element's background image, until the parent <li> is subject to the :target selector.
  2. At that point, the .a.close-img displays with fixed positioning, and the large background image is requested, and centered via some background CSS properties—much easier than fiddling around with padding or margins, IMO.
  3. If the image is larger than the viewport, it is restricted by background-size: contain which unfortunately requires an !important flag.
  4. The other drawback is the requirement of an inline style attribute, if you want to dynamically set the background image. These two minor concessions seemed worth it to me, in order to achieve all the requirements listed above.
  5. The anchor elements all have valid href attribute values, with # anchor links to toggle the :target state. That is the only interaction required to hide/show the large images.

There are more details in the code comments of the working demo, for those who are curious, but that's about all there is to it. It's small and cross-browser compatible back to IE 7 or 8.