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 flexbox, 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 JavaScript 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