Get our posts emailed to you with our monthly newsletter, subscribe here.

Freelancers and designers are often looking for ways to spice up a typical portfolio layout. You want to show off your most recent works to potential clients, while also offering a quick way to learn about your talents and get in contact. Single-page layouts are great if you have the design capability. But there are also other unique types of portfolio user interfaces which are stunning as well.

Divi WordPress Theme

In this tutorial I want to demonstrate how we can build a dynamic filtered portfolio list using jQuery. To speed up the development process we can use a jQuery plugin Quicksand to help with the sorting animations. This is a lucrative method for people who build various types of products and want to showcase their work together in one place. You could also link the portfolio images to display embedded text or photobox modal windows.

Live Demo PreviewDownload Source Code

Getting Started

First create a new directory for the project code and download the latest quicksand plugin off Github. The master repo will always contain the most recently updated version, as new commits are pushed by other coders o the original developer. Now create a new blank index.html file which will be the container for our webpage.

I am going to use the typical HTML5 doctype with a few 3rd party resources. Aside from the Quicksand plugin we also need a copy of jQuery and also the html5shiv library isn’t a bad idea either. For sprucing up the typography I’ll include a Google Webfont named Kite One. This will be used in the sorting options menu.

<!doctype html>
<html lang="en-US">
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
  <title>Dynamically Sorted Portfolio Demo</title>
  <meta name="author" content="Jake Rocheleau">
  <link rel="stylesheet" type="text/css" href="styles.css">
  <link rel="stylesheet" type="text/css" href="">
  <script type="text/javascript" src=""></script>
  <script type="text/javascript" charset="utf-8" src="jquery.quicksand.js"></script>
  <script type="text/javascript" charset="utf-8" src="sorting.js"></script>
<!--[if lt IE 9]>
  <script type="text/javascript" src=""></script>

Notice that aside from all these remote scripts I have also included two more of my own files. The first stylesheet styles.css will contain all the CSS details for our layout. Then sorting.js has some basic jQuery we need to perform as the user clicks each link. You have the choice to include this code right into your HTML page using script tags, but I feel using a separate file keeps it all cleaner.

Building the Layout

Let’s move down into the HTML body code where all the content is placed. I won’t copy over everything since much of the portfolio listing is redundant. But it is crucial to understand the different attributes we are setting and how these affect Quicksand.

<div class="sort" id="sort">
	<span class="label">Filter By:</span> <a href="#" class="all selected">All</a> <a href="#" class="web">Web</a> <a href="#" class="ios">iOS</a> <a href="#" class="print">Print</a>

<ul class="portfolio clearfix">
  <li data-id="id-1" class="ios"><a href="" target="_blank"><img src="images/ios-app-ui-01.png" class="portimg"></a></li>
  <li data-id="id-2" class="print"><a href="" target="_blank"><img src="images/print-design-cards.png" class="portimg"></a></li>

Inside the wrapper class we have two main child elements. First the div with a class .sort which holds all four of our sorting links. The class names are relative to how I have labeled each of the portfolio items. The link with an added class of .selected will appear to be the current filter.

The .portfolio class is actually applied directly to the <ul> element. Inside you will find each list item is using the data-id HTML5 attribute syntax in the format of id-#. These ID numbers are required for Quicksand to operate properly by hiding/showing individual items.

Also you should notice how each list item is given a matching class related to a link sorting option. I haven’t used any of these classes for CSS styles, so I decided we can sort the portfolio items using this class value. However if you need to keep your classes separate you can use another attribute such as data-name to hold your sorting options.

Custom CSS Page Styles

Moving inside the stylesheet document I have included a slightly updated version to the more generic Eric Meyer’s reset. What is really important here is how I am styling the portfolio items as they are floating inside the unordered list. But first we can take a quick peek at the filter links.

/* main page layout */
#w { display: block; min-width: 850px; max-width: 1150px; margin: 0 auto; padding: 0 15px; padding-top: 45px; }

/* sorting and filtering */
.sort { display: block; font-family: 'Kite One', Arial, sans-serif; font-size: 1.4em; line-height: 0.9em; color: #444; }

.sort .label { margin-right: 11px; }

.sort a { margin-right: 4px; padding: 0px 3px; }
.sort a:hover { color: #989caa; text-decoration: none; border-bottom: 1px dotted #989caa; }

.sort a.selected { color: #85878f; border-bottom: 1px solid #85878f; }

You will notice the .sort menu is where I’m applying this custom Google font into the document. Just using very basic grey/dark grey colors and a border to denote selected items. You could ultimately place this sorting menu anywhere in your layout and still have Quicksand working properly.

/* portfolio items */
.portfolio { display: block; margin-bottom: 10px; padding-top: 20px; width: 100%; }

.portfolio li { 
  float: left; 
  margin-right: 18px; 
  margin-bottom: 1.55em;
  -webkit-box-shadow: 1px 2px 3px rgba(0,0,0,0.45);
  -moz-box-shadow: 1px 2px 3px rgba(0,0,0,0.45);
  box-shadow: 1px 2px 3px rgba(0,0,0,0.45);
.portfolio li a { 
  display: block; 
  padding: 4px; 
  background: #fff; 
  border: 1px solid #ccc; 
  -webkit-transition: all 0.35s linear; 
  -moz-transition: all 0.35s linear; 
  -o-transition: all 0.35s linear;
  transition: all 0.35s linear;
.portfolio li a:hover { opacity: 0.65; }

On the container .portfolio I have added a display: block; property so the whole element takes up the full width of our page. But the problem is that list items are floating left which removes them from the typical page flow. This means as you would resize the links they would all float over to the left before appearing back into a grid.

The way we fix this is by adding width: 100%; onto the portfolio container. Now it will stay the same width as the page no matter if the whole list is empty or floating. We also use some nice CSS3 transitions on the anchor hover to fade out opacity.

Working with Quicksand jQuery

Let’s finally move onto the JavaScript side where we setup the portfolio filtering. I want to first create the click event listener tied to all the anchor links inside our sort container. Then we need to disable the HREF value and instead perform our custom sorting method.

  var pclone = $(".portfolio").clone();

  $("#sort a").on("click", function(e){
    var sorttype = $(this).attr("class");

The var pclone is a portfolio clone variable which contains a cloned jQuery object. We use this to quickly access the full list of portfolio items instead of messing with the already-existing DOM elements. Also I am setting another variable sorttype which checks the current anchor links’ class value. This is the value we need to filter into the portfolio listing and find similar matches.

// determine if another link is selected
if(!$(this).hasClass("selected")) {
  $("#sort a").removeClass("selected");

// check filter sort type
if(sorttype == "all") {
  var filterselect = pclone.find("li");
} else {
  var filterselect = pclone.find("li[class="+sorttype+"]");

The final piece of our script is split into two logic statements. First we need to check if any other anchor links already have the class .selected. If this is true then we run .removeClass(“selected”) on all the sorting anchor links to make sure we have nothing selected. Then set a new selected class to the recently clicked element.

The 2nd block of code is checking against our current sorttype variable. If we are calling all the elements back into view then we only need to filter for regular list items(<li>). Otherwise we need to find only list items with a matching class value. Either way we get a new variable filterselect which is passed into our Quicksand method call.

  adjustHeight: 'auto',
  duration: 550
}, function() { 
  // callback function

This brief function is all we need to run the final sorting command. All the other logic statements are important to determine which type of content is being filtered. Using the adjustHeight parameter will keep duplicate content from taking up excess page space. Also the duration may be edited to any value that you like, formatted in milliseconds. The callback function should contain any codes you want to run after the filtering is complete, but you can leave it blank too.

Have a look at my demo example below to see how this all comes together. I configured this demo using most of the default settings to make it easier to follow. But have a look at the Quicksand documentation to better understand some of the extra parameters. For example, if you include the jQuery easing plugin you can alter the type of animation effect to any other provided options – or even create your own!

Live Demo Preview – Download Source Code

Final Thoughts

If you play around with the Quicksand demo page you can learn a lot about how the plugin operates. All of the CSS styles and positioning can be determined remotely on your own layout. It does take a bit of tinkering to get all the bugs worked out, but the final result is fantastic.

I hope this tutorial can prove useful to any developers looking to create a sorted webpage list. The dynamic animations are aesthetically beautiful and offer a rich user experience. Plus the system utilizes HTML5 attributes which are still unique to many web developers. If you have any further thoughts or questions on the tutorial drop a comment in the discussion area.

Posted by Jake Rocheleau

Jake is a freelance writer, designer, and illustrator. He currently writes articles on user experience design and web development techniques. You can check out his work on Dribbble and follow his tweets @jakerocheleau.


  1. Great way to sort projects, good job!

    Two questions, is it possible for a project to show up in multiple categories? i.e. a project could be both web, print and iOS?

    Also, is it possible to list the other projects below, somehow “greyed out”, but still clickable? This isnt as important as the first one, very important to show you can create projects that span several to all categories (360).

  2. Hi, great tutorial.

    I have however run into a problem getting this to work on my wordpress theme.The filtering doesn’t seem to work at all but everything else is perfect. I’m assuming the javascript files need to be called using php for a template file given that I couldn’t get it to work before? Currently I’m using this to call the files

    <script type="text/javascript" src="jquery.quicksand.js”>

    Any help would be much appreciated as I still haven’t gotten it working.

    1. You will need to update the src=”” to point towards your theme directory, or wherever you store javascript files. Just open the folder where you place jquery.quicksand.js and copy that in front and it should work fine.

    2. Hi Jake,

      I’ve tried that with variations of

      as well as

      and it still doesn’t seem to want to filter. Any thoughts on what I’m doing wrong?

      Also I’m trying to center the grid on my page at various sizes as it’s a responsive website. I’m finding that the thumbnails due to their size don’t center properly when it can’t fit a whole one to the right it just leaves a gap which looks a bit odd. Any way I can counteract this? You can see the page I mean here

      Thanks for your help,

    3. Sorry, the comment box appears to have eaten my example code. I’ve tried:


      as well as

  3. Thank you for this tutorial. I found it very easy to understand and grasp. I’ve run into one issue however and I’m not quite sure how to fix it.

    I have each set to be 100% width for screen widths<400px, and 50% for screen widths<400px via media queries. I can switch between each (eg. portrait to landscape on a phone) with the ‘s updating widths but if I click to filter the ‘s, the ‘s stop updating when I change screen widths. Is there any reason for this or a way you know to stop this from happening?

    Thanks, and again awesome tutorial! :)

    1. Seems that each time I mentioned the list items the word got removed, sounds a little weird with them missing!

  4. Great tutorial! I’ve just implemented something similar using Quicksand for a WordPress theme I’m working on.

    Will fill some knowledge gaps for a few people as the Quicksand documentation is lacking.


  5. Whats with jQuery’s native .fadeIn(), .fadeOut(); Functions?

    Just give those sorting Links a simple Click Function (IOS-Link for Example):


    Little Snippet of Code!

Comments are closed.