I'm Dudley Storey, the author of Pro CSS3 Animation. This is my blog, where I talk about web design and development with HTML, CSS and SVG. To receive more information, including news, updates, and tips, you should follow me on Twitter or add me on Google+.

my books

Pro CSS3 Animation book coverPro CSS3 Animation, Apress, 2013

my other blogs

Massive Head CanonMassive Head Canon: Intelligent discussion of movies, books, games, and technology.

my projects

The New DefaultsThe New Defaults — A Sass color keyword system for designers.

CSSslidyCSSslidy — an auto-generated #RWD image slider. 3.8K of JS, no JQuery.

Sorting Page Content With JavaScript

Easy animated ordering of web page elements with no JQuery or plugins.

Some of my layout articles, especially those that show items arranged with flexbox or CSS columns, have generated questions about the possibilities of reordering content. While flexbox has the ability to reorder items, the flexbox module is generally intended for changes to UI, rather than reordering based on arbitrary criteria.

In this article, I’ll show how you can easily arrange items alphabetically and chronologically on a page; in turn, you could use the same principles to order items using any kind of criteria.

It’s important to understand that this is true reordering of content, i.e. moving from ABCDE to CBADE. If you want to simply filter content – removing the B & D elements from ABCDE so that the user sees ACE – I’ve shown ways of doing that in previous articles.

Determining The Data Source

There are four sources of data that we could use to as a key to reorder elements:

  • Use the content: easiest to write HTML for, but slightly tricky to implement, and the hardest to keep consistent. Content keys are used in this example.
  • We could use data that already exists in the markup, such as required attributes and their values. This may include information that has been added to the markup, such as data attributes.
  • We could also use data that exists outside the HTML page, such as a database, when ordering large information sets.

To start, I’ll create the markup, enhanced with a little microdata. For this example, I’m using paintings of the French Revolution:

<div id="rev-works">
<figure itemscope itemtype="http://schema.org/Painting">
<img src="the-death-of-marat.jpg" alt itemprop="image">
<figcaption itemprop="name">The Death of Marat</figcaption>
<div>
<span itemprop="creator">Jacques-Louis David</span>
<time itemprop="dateCreated">1793</time>
</div>
</figure>
</div>

Only one painting is shown here, as all the other works take the same pattern. You can see we have several possible content keys to use, including the date of creation and the artist’s name.

The CSS

While styling the content isn’t our focus here – there are plenty of ways to place the content side-by-side – this is the basic stylesheet I’m using:

#rev-works, #rev-works figure div { display: flex;  align-items: flex-start; }
#rev-works figure { flex: 1; background: #fff; padding: 10px; }
#rev-works figure img { width: 100%; height: auto; }
#rev-works figcaption { margin: 1rem auto; text-align: center; font-weight: 700; }
#rev-works figure div { justify-content: space-between; }

The Menu

We need a UI element to allow the user to sort the content. This could be practically anything, from links to buttons, but in this case I’ll use a <select> drop-down:

<label for="orderby">Order by:</label>
<select name="orderby" id="orderby">
<option value="theme">Theme</option>
<option value="artist">Artist</option>
<option value="date">Date</option>
</select>

(I’m assuming that the default order of the paintings corresponds to a theme.)

Ideally the <select> element would be injected into the page with JavaScript, since what we’re about to do requires JavaScript in any case: there’s no point in presenting an element to visitors that they can’t use.

The JavaScript

The basic script is placed at the end of the document:

var theme = document.getElementById("orderby"),
paintings = document.getElementById("rev-works"),
figures = paintings.querySelectorAll("figure"),
original = paintings.innerHTML;
function sortUs(parent, child, key) {
var items = Array.prototype.slice.call(document.querySelectorAll(parent + " " + child)).sort(function(a, b) {
var comparA = a.querySelector(key).innerHTML;
var comparB = b.querySelector(key).innerHTML;
return (comparA < comparB) ? -1 : (comparA > comparB) ? 1 : 0;
});
for (var i = 0; i < figures.length; i++) {
paintings.appendChild(items[i]);
} }
theme.onchange = function(){ 
if (theme.value == "theme") { 
paintings.innerHTML = original;
} else {
if (theme.value == "artist") { el = "span[itemprop=creator]"; }
if (theme.value == "date") { el = "time"; }
sortUs("#rev-works","figure",el);
} }

I’m not going to explain every aspect of the code here: that’s for future articles. For now, it’s enough to note the following:

  • The central function is the parametrized sortUs, which takes three arguments: the parent element, the children elements to reorder, and the key.
  • The innerHTML – that is, the content from a particular element inside each <figure> is taken as the key, and sequentially compared to each other to determine the order of the <figure> elements that contain them.

Adding Easing

The code works, but the UX is all a little sudden and brutal, with elements appearing and disappearing suddenly. With a little more work you could add a sequential fade-in effect; the code to do that is available in this article’s CodePen repo.

Responsiveness & Conclusion

One of the nice aspects of using flexbox is that it easily transfers to presenting the paintings in “portrait” mode when the browser window narrows: the script changes the physical order of elements, which flexbox respects.

Hopefully this small piece of code has shown that you don’t necessarily need JQuery or frameworks like IsoTope or TinySort to create dynamic sorted content on your pages. See the complete code for this gallery on CodePen

This site helps millions of visitors while remaining ad-free. For less than the price of a cup of coffee, you can help pay for bandwidth and server costs while encouraging further articles.