Responsive CSS3 Modal Gallery (with JavaScript keyboard controls)
This is version 3. Also see all other versions to see how this gallery evolved.
This is version 3 of the responsive gallery, which is a progression of its CSS-only counterpart (version 1) and uses a few lines of JavaScript to load the larger images on demand only, instead of during initial page load. This has the benefit of speeding up the web page to optimise front-end performance. A <noscript> fallback is provided for when JavaScript is turned off. Please read the Notes section for details about JavaScript enhancement and knock-on UX considerations.
Further to the version 2 modal gallery with JS on-demand images, keyboard navigation has now been added to provide left and right arrow movement through the image enlargement lightbox. The escape key closes the modal overlay.
Click on an image below to bring the gallery to life (and resize the browser window for slinky responsiveness)...
Features
A CSS3, responsive image gallery that;
- Opens an image enlargement in a modal overlay/lightbox (by using the :target selector)
- Has "previous" and "next" controls to cycle through the gallery from within the modal overlay/lightbox
- Includes keyboard navigation to move back and forth through the gallery from within the modal overlay/lightbox
- On a small screen, the "previous" and "next" controls become extra large tappable areas for easy finger jabbing
- Uses CSS3 transitions to animate a gentle fade effect (on thumbs and modal overlay/lightbox)
- Includes optional image captions (inside the modal overlay/lightbox)
- Loads larger versions of the images on demand (with a snippet of JavaScript) instead of during initial page load
- A <noscript> fallback allows image enlargements to be opened in a new window when JavaScript is disabled
- Shows a CSS3 loading spinner to indicate that larger images are loading
Please view the source of this web page to grab the JS, CSS and HTML markup.
Pros
- Loads larger versions of the images on demand (with a snippet of JavaScript) instead of during initial page load.
- You can bookmark or link to a larger image and it will load inside the modal overlay/lightbox (e.g. gallery-modal-rwd-nav-js.htm#pic-1).
- Browser history is not affected while viewing image enlargements, thanks to JavaScript's location.replace() method.
- A <noscript> fallback allows larger images to be opened in a new window when JavaScript is disabled.
Cons
- Extra markup for the IE7/8 workaround. You can use something like Selectivizr to make older IE recognise the :target selector, but that is outside the scope of this demo, although here is a gallery demo using Selectivizr for IE8 support.
- Extra <noscript> markup for when JavaScript is disabled; Larger images will open in a new window.
Use of :target affects the browser history; Each big picture viewed will add something like "#pic-1" at the end of an URL, and will be cycled back through when the browser's back button is clicked.- Use of "data-src" in place of "src" in the <img> tag invalidates markup.
Notes (JavaScript to load larger images on demand + keyboard controls)
The main change to the CSS-only version of the gallery is the inclusion of an "onclick" event on hyperlinks (on the thumbnail image, and on "previous", "next" and "close" controls), and a corresponding "id" on the <img> tag that holds the larger image. All href attributes (except those supporting IE7/8 and <noscript>) have also been removed, turning gallery navigation links into placeholder links. URL hashes are instead handled in the onclick load() function, with the location.replace() method;
<!--[if gte IE 9]><!--><a onclick="load('img-1')"><!--<![endif]--> <!-- no href - use location.replace('#pic-'+id); in load() function -->
<!--[if lte IE 8]><a href="/path/to/big/image.jpg" target="_blank"><![endif]-->
<noscript><a href="/path/to/big/image.jpg" target="_blank"></noscript>
<img src="/path/to/small/thumb.jpg" width="252" height="160" alt="" />
<span><b>Preview</b></span>
</a>
<div id="pic-1" class="overlay">
<img id="img-1" class="big-img" data-src="/path/to/big/image.jpg" alt="" /> <!-- no size attributes - keep it responsive -->
<div>
<p>Here is an interesting caption for the big image.</p>
</div>
...
Also note HTML5's "data-src" attribute which is now referencing the larger image instead of a standard "src" attribute. With "data-src" in place, the image will not load until the snippet of JavaScript below changes it to "src" when the corresponding link is clicked, and so the large image is only loaded when it is requested. The ".big-img" class in the markup above is used in the JavaScript keyCheck() function for keyboard nav controls (see the source code of this web page for that particular script);
function load(myimg){ // load larger img
var img = document.getElementById(myimg); // get img id
img.src = img.getAttribute("data-src"); // switch "data-src" to "src" on corresponding img
id = myimg.replace(/^\D+/g, ''); // get number id from img id ("#img-1") ready for arrow key nav
location.replace('#pic-'+id); // go to hashed url without affecting browser history
document.onkeydown = galleryNav; // start arrow key nav
}
By also including the following 2 lines of JavaScript, you can capture the hash on the end of an URL, strip it back to the "id" of the larger image, and load it in via a link or bookmark when the page loads. Without them you would not be able to bookmark a larger image because the targeted URL wouldn't include the onclick JavaScript call that changes "data-src" to "src" in the <img> tag. However, even without these extra 2 lines of script, you could still link to a larger image if you include the onclick JavaScript call in the anchor <a> tag (e.g. href="gallery-modal-rwd-nav-js.htm#pic-1" onclick="load('img-1')";
var id = window.location.hash.substr(1).replace(/^\D+/g, ''); // get hash from url ("#pic-1") and get number id
if (id) { load('img-'+id); } // load larger img
UX consideration 1... what happens when JS is disabled?
The deleted chunk of info below can be ignored now that alternative markup is included in <noscript> tags. Thinking along the same lines as the IE7/8 workaround (more on that later), where those users can open image enlargements in a new browser window instead of the modal overlay/lightbox, we can do something similar for folks with JavaScript turned off;
<!--[if gte IE 9]><!--><a onclick="load('img-1')"><!--<![endif]--> <!-- no href - use location.replace('#pic-'+id); in load() function -->
<!--[if lte IE 8]><a href="/path/to/big/image.jpg" target="_blank"><![endif]-->
<noscript><a href="/path/to/big/image.jpg" target="_blank"></noscript>
<img src="/path/to/small/thumb.jpg" width="252" height="160" alt="" />
<span><b>Preview</b></span>
</a>
The main issue when JavaScript is off is that the CSS :target-powered modal overlay/lightbox will still open, but there will be no script-powered image enlargement inside. Yuk! So, the best UX workaround I can come up with in CSS is to stop the empty #gallery .overlay from opening, and disable visual cues on thumbs (i.e. hover effect, cursor and pointer-events);
#gallery .overlay:target { /* width:auto; height:auto; bottom:0; right:0; */ padding:0.5em 0 5em }
/* overlay size/position disabled - see below for when js is on */
...
/* #### - extra css for js enhancement - #### */
#gallery li a { pointer-events:none; cursor:default } /* disable pointer-events and cursor on gallery thumbs ... */
.js #gallery li a { pointer-events:auto; cursor:pointer } /* ... and enable them again when js is on */
#gallery li a:hover span { display:none } /* disable hover effect on gallery thumbs ... */
.js #gallery li a:hover span { display:inline-block } /* ... and enable it again when js is on */
.js #gallery .overlay:target { width:auto; height:auto; bottom:0; right:0 } /* overlay enabled when js is on */
Unfortunately, pointer-events are unsupported in IE10 and under, so for IE9/10 users who also have JavaScript disabled, they'll rack up void URLs in the browser history if they click on the, now seemingly inactive, thumbs.
IE7/8 fairs better here, and users will be unaffected if they have JS disabled due to the alternative markup; IE conditional comments for hyperlinks that open larger images in a new window. The only consideration for IE7/8 now is to reverse the above CSS in a conditional stylesheet so that users still see the thumb image hover effects and pointy-fingered link cursor;
<!--[if lt IE 9]>
...
#gallery li a { cursor:pointer } /* reverse the extra css used for js enhancement */
#gallery li a:hover span { display:inline-block } /* reverse the extra css used for js enhancement */
<![endif]-->
UX consideration 2... is it loading?
The "on-demand" image script takes care of the performance dilemma (thumbs up for mobile), but it could leave users with slower internet connections wondering when that big ol' image is going to appear on their screen. So let's add a simple loading spinner to indicate something is happening... Add this to the CSS;
@-webkit-keyframes rotation { from {-webkit-transform:rotate(0deg)} to {-webkit-transform:rotate(359deg)} }
@keyframes rotation { from {transform:rotate(0deg)} to {transform:rotate(359deg)} }
#gallery .overlay:before {
content:"";
position:absolute;
top:40%;
margin-top:-0.5em;
left:50%;
margin-left:-2em;
display:block;
height:3em;
width:3em;
border:0.5em solid rgba(255,255,255,.15); border-top:0.5em solid rgba(255,255,255,.5); border-radius:100%;
-webkit-animation:rotation .75s infinite linear; animation:rotation .75s infinite linear
}
This places a CSS pseudo element loading spinner on the #gallery .overlay. It's always present, but then when an image has loaded, the picture will sit in front of the spinner and hide it!
Compatibility
- IE7+ *
- Chrome
- Safari
- Firefox
- Opera
- Android
- iOS
* The :target selector is not supported in IE7/8 but a bit of markup-mashing with IE conditional comments provides a workaround so those users can open image enlargements in a new browser window instead of the modal overlay/lightbox.
<!--[if gte IE 9]><!--><a onclick="load('img-1')"><!--<![endif]--> <!-- no href - use location.replace('#pic-'+id); in load() function -->
<!--[if lte IE 8]><a href="/path/to/big/image.jpg" target="_blank"><![endif]-->
<noscript><a href="/path/to/big/image.jpg" target="_blank"></noscript>
<img src="/path/to/small/thumb.jpg" width="252" height="160" alt="" />
<span><b>Preview</b></span>
</a>
* IE7/8 users will not see the magnifying glass icon when they hover over a thumbnail. However, there is fallback for a plain "Preview" bar that they will see instead.
I haven't been able to test in other browsers/devices but feedback is always welcome. Contact me if you spot anything hinky.
Acknowledgement
Inspired by the "CSS3 Modal Popups" tutorial at Script Tutorials.
Related
- Version 1: Responsive CSS3 Modal Gallery (no JavaScript)
- Version 2: Responsive CSS3 Modal Gallery (with JavaScript on-demand images)
- Version 4: Responsive CSS3 Modal Gallery (with JavaScript on-demand images, keyboard controls + pagination)
- Version 5: PHP Responsive CSS3 Modal Gallery (with JavaScript on-demand images, keyboard controls + pagination)
Freebies
Looking for more freebies for your website? Grab a bunch of free PHP, CSS and JavaScript goodies, from flat file CMS' to RSS managers to responsive CSS menus, galleries and sliders.