A closeup of the head of a swimming polar bear, shot underwater
A photograph of a sitting tiger cub
Photograph of a male lion lying on green grass
Closeup photograph of a tiger
Photograph of a swimming polar bear, shot from underwater and underneath
A photograph of a sitting lion and lioness in profile

While I’ve shown filtered responsive image galleries in the past, they don’t have the dynamism that some designers desire. Of course, it’s easy to take “dynamism” too far, into what I refer to as “swooshy-swooshy” UI, with massive dependencies on frameworks and plugins and everything on the page whirling about in confusion.

This gallery code seeks balance: a straightforward UI coupled with non-disorienting animation. Along the way, we can learn a few things about making progressively enhanced UI elements.

The HTML & CSS

The markup and styles are fairly straightforward: each gallery image is placed inside a <figure> element, which in turn are placed inside a <div>. Another <div>, empty to start, is placed at the top to receive our UI.

<div id="selectionbar"></div>
<div id="dynaflex">
	<figure data-group="bears">
        <img src="polar-bear-closeup.jpg" alt>
    </figure>
    <figure data-group="tigers" class="cub">
        <img src="tiger-cub.jpg" alt>
    </figure>
    <figure data-group="lions" class="on-grass">
        <img src="lion-on-grass.jpg" alt>
    </figure>
    <figure data-group="tigers">
        <img src="tiger.jpg" alt>
    </figure>
    <figure data-group="bears">
        <img src="polar-bear-swimming.jpg" alt>
    </figure>
    <figure data-group="lions">
        <img src="lion-and-lioness.jpg" alt>
     </figure>
</div>

Each image is categorised with a data- attribute value on the <figure> that contains it. Because we’ll be using , each image must be the same aspect ratio, or manipulated via its flex CSS value to be consistent with the others. You could use my “Modern Masonry” script to do so, or manually adjust the images through the addition of classes.

#dynaflex { 
	display: flex; font-size: 0;
	flex-flow: row wrap; 
}
#dynaflex figure { 
	margin: 0; min-width: 201px;
	flex: 0.67; transition: .5s; 
}
#dynaflex figure img { 
	width: 100%; height: auto; 
}
#dynaflex figure.cub {
	flex: 0.568; min-width: 170.49px; 
}
#dynaflex figure.on-grass { 
	flex: 1; min-width: 300px; 
}
#dynaflex figure.diminish { 
	min-width: 0; flex: 0; 
}

Somewhat surprisingly, the flex value of elements can be animated: we’ll be doing that by using to add and remove the .diminish class.

The JavaScript

After identifying elements on the page for the script, we create an empty categories array, which collects together the all data-group values used by <figure> elements. unique then filters the array to keep only unique values, reverses it (to get the result ["lions", "tigers", "bears"]) before adding all as the first array value.

var container = document.getElementById("dynaflex"),
array = container.getElementsByTagName("figure"),
selectionBar = document.getElementById("selectionbar"),
categories = [];
for (var i = 0; i < array.length ;i++) {
categories[i] = array[i].dataset.group;
}
var unique = categories.filter(function(item, i, ar){
	return ar.indexOf(item) === i; 
});
unique.reverse();
unique.unshift("all");

Create A Progressive Dropdown

Next, we need to create the dropdown that will be used to actively filter the images:

var dropdown = document.createElement("select");
dropdown.id = "categories";
var dropdownLabel = document.createElement("label");
dropdownLabel.for = dropdown.id;
dropdownLabel.innerHTML = "Show : ";
unique.forEach(buildDropDown);
selectionBar.appendChild(dropdownLabel);
selectionBar.appendChild(dropdown);

You can see the line that uses the ECMAScript5 forEach method to call on the buildDropDown function, which is as follows:

function buildDropDown(name,index,array) {
var opt = document.createElement("option");
opt.value = name;
opt.innerHTML = name;
dropdown.appendChild(opt);
}

The function builds a dropdown menu with the values of unique. Now we just need to react when the menu is used:

dropdown.onchange = function() {
	if (this.value == "all") { 
		for (var i = 0; i < array.length; ++i) {
array[i].classList.remove("diminish");
		}
	} else {
		var hide = document.querySelectorAll('#dynaflex figure:not([data-group="'+this.value+'"])');
		for (var i = 0; i < hide.length; ++i) {
hide[i].classList.add("diminish");
		}
		var show = document.querySelectorAll('#dynaflex figure[data-group="'+this.value+'"]');
		for (var i = 0; i < show.length; ++i) {
show[i].classList.remove("diminish");
		}
	}
}

While the animation isn’t as smooth as I’d like it to be, and does not render completely correctly in Mobile Safari (due to a bug in the browser that affects images approaching their min-width dimensions) I think the approach has promise… and on the whole, the result is a lot better than dependency on a framework and plugin.

Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/pzhmn