Rose Red Wine
Green Glass Bottle
Guinness Barrels, Dublin
Crystal Skull Vodka

A little gallery I was inspired to pull together last night: four images arranged in a rectangle, each transitioned to a larger size on a click, with captions.

The markup uses <figure> elements inside a <div>. alt attributes have been minimized to save space:

<div id="quad">
		<img src="rose-red-wine.jpg" alt>
		<figcaption>Rose Red Wine</figcaption>
		<img src="guiness-barrels.jpg" alt>
		<figcaption>Barrels of Guinness, Dublin</figcaption>
		<img src="green-glass-bottle.jpg" alt>
		<figcaption>One Green Bottle</figcaption>
		<img src="crystal-skull-vodka.jpg" alt>
		<figcaption>Crystal Skull Vodka</figcaption>

The initial CSS ensures that the images remain side-by-side with each other at the correct aspect ratio:

div#quad {
	background-color: #111;
	font-size: 0;
	width: 50%;
	margin: 0 auto;
div#quad figure {
	margin: 0;
	width: 50%;
	height: auto;
	transition: 1s;
	display: inline-block;
	position: relative;
div#quad figure img {
	width: 100%;
	height: auto;

Next, we make sure that each <figure> is transformed from its far corner, relative to its overall container. Vendor prefixes have been removed for clarity:

div#quad figure:nth-child(1) {
	transform-origin: top left;
div#quad figure:nth-child(2) {
	transform-origin: top right;
div#quad figure:nth-child(3) {
	transform-origin: bottom left;
div#quad figure:nth-child(4) {
	transform-origin: bottom right;

Finally, the CSS for the presentation of the captions and the full-width elements:

div#quad figure figcaption {
	margin: 0;
	opacity: 0;
	background: rgba(0,0,0,0.3);
	color: #fff;
	padding: .3rem;
	font-size: 1.2rem;
	position: absolute;
	bottom: 0;
	width: 100%;
	transition: 1s 1s opacity;
.expanded {
	transform: scale(2);
	z-index: 5;
div#quad figure.expanded figcaption {
	opacity: 1;
div.full figure:not(.expanded) {
	pointer-events: none;
div#quad figure:hover {
	cursor: pointer;
	z-index: 4;

These styles are perhaps best understood in the context of the JavaScript that is applied at the end of the document:

var quadimages = document.querySelectorAll("#quad figure");
for (i=0; i<quadimages.length; i++) {
	quadimages[i].addEventListener( 'click',  function() {

When the user clicks or touches small image, it is expanded to a full-width presentation with an applied class. The z-index associated with this state ensures that the image is always on top of the others, further guaranteed by removing pointer events from the other images at the same time.

The only condition is that all the images must be exactly the same size; in theory, this could be applied to a system of six or more images with appropriate transform-origin settings, so long as their aspect ratios matched.

Images by Pete Slater, Christina Ann VanMeter, Jen Scheer and  Shadi Samawi, licensed under Creative Commons.

Enjoy this piece? I invite you to follow me at to learn more.
Check out the CodePen demo for this article at