With growing adoption of srcset & sizes for responsive images we can let the browser do the work of choosing optimum image sources for both the gallery thumbnails and the full size images with just a single <img>
definition. We just need a little JavaScript to update the sizes
attribute when the layout changes for our lightbox view.
Demo: blinkcursor.github.io/mv-gallery/
<a href="img/nojs-fallback.jpg">
<img src="img/unsupported-fallback.jpg"
srcset="img/smallest.jpg 400w, img/smallish.jpg 600w, img/small.jpg 800w, img/medium.jpg 1000w, img/biggish.jpg 1200w, img/big.jpg 1400w, bigger.jpg 1800w, biggest.jpg 2400w"
sizes="(max-width: 399px) 100%, (max-width: 599px) 50%, (max-width: 799px) 33.33%, 200px" alt="sample image">
</a>
The sizes
definition is for our gallery (thumbnails) view. When the user clicks on a thumbnail we launch a modal lightbox and populate it with a clone of the thumbnail, but before inserting it into the DOM we dynamically update sizes
to the value appropriate for the modal and let the browser select the best image source.
For our baseline, sizes
for a full-width modal would be 100vw
, but we can be smarter than that.
The modal uses max-height: 100%
and max-width: 100%
to constrain our full-sized images to fit on the screen.
But any image whose aspect ratio is smaller than the screen aspect ratio won't occupy the full width of the screen, and sizes: 100vw
will overstate how much width the image will occupy.
Think portrait images on a laptop screen, which might occupy 50% or less of the available width according to sizes
, and which results in the browser selecting a much larger image than required.
When cloning our thumbnail image we know its aspect ratio which gives us a chance to compute a more relevant sizes
value by comparing it to the screen aspect ratio.
Safari (OSX and iOS) is a problem. It has a bug whereby the sizes
attribute is present on <img>
elements, but the sizes
property is missing and any attempt to dynamically update sizes
is ignored. As a workaround for Safari we parse srcset
ourselves to find the appropriate size and set the src
on a new image instead.
The are no markup requirements for your gallery. Just wrap some <img>
's in a container and pass the query selector for your container to mvGallery.init(selector)
.
The source code is in src/js/mvgallery.js.
It has two dependencies.
- src/js/plugins/swipe-detect.js is a crude touch event handler written specifically for mv-gallery to add swiping between images. IRL you might want to use a dedicated touch handling library like hammer.js and modify mvgallery.js accordingly.
- parse-srcset by Alex Bell for the Safari bug workaround.
In /dist these are bundled with mvgallery into mvgallery-bundle.min.js
, while mvgallery.min.css
has the minimal styling required for the modal lightbox. (How you style your gallery is up to you.)
Link to mvgallery.min.css
in your document <head>
and include mvgallery-bundle.min.js
just before your closing </body>
tag, then instantiate with mvGallery.init('selector')
.
Nothing fancy here. In production this would benefit from some nice transitions when navigating between images, and use of the History API to allow linking directly to individual images when shared etc.
As well as concatenating and minifying the source files, the gulpfile
includes a task to automatically generate all of the different image sizes from source images found in the src/img
directory. The example should be self-explanatory.