Single-Page Ajax Portfolio Update Panel with jQuery

by Jake Rocheleau

on November 28, 2012

in Tutorials

Get the FlatPix UI Kit for only $7 - Learn More or Buy Now

Building your own custom portfolio website can be tough. Freelancers are often stuck looking for work and trying to land projects without prior experience to showcase. But if you can put together even a simple gallery of practice works, your potential clients will be a lot more impressed.

In this tutorial I want to explain how we can build a simple portfolio update panel using jQuery. For this demonstration I am using some beautiful illustrations from Nidhi Chanani. You will notice the webpage itself is very bare aside from the effect. This will make it easier to embed a similar page widget into any portfolio layout.

Preview screenshot portfolio jQuery live update panel graphics artwork

Getting Started

Let’s start with the typical HTML page setup using an HTML5 doctype. I have also included an external stylesheet and JavaScript file. Plus we will need to include the latest CDN version of jQuery to animate fade effects.

<!doctype html>
<html lang="en-US">
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
  <title>Single-Page Portfolio Update Panel Demo</title>
  <meta name="author" content="Jake Rocheleau">
  <link rel="shortcut icon" href="">
  <link rel="icon" href="">
  <link rel="stylesheet" type="text/css" href="styles.css">
  <link rel="stylesheet" type="text/css" href=",700">
  <script type="text/javascript" src=""></script>
  <script type="text/javascript" charset="utf-8" src="script.js"></script>
<!--[if lt IE 9]>
  <script src=""></script>

For the main body section I have split the layout into two pieces. The top portion contains our set portfolio header with a textured blue background. This is set to a fixed height to keep the whole layout pixel-perfect. You may also notice that all the images are added into the code from the start. As you click on each link the images are displayed alternately.

  <div id="display">
    <div class="wrapper">
      <div id="preview">
        <img src="images/01-after-the-storm.png" id="01" >
        <img src="images/02-the-cake-tree.png" id="02" >
        <img src="images/03-the-great-pumpkin.png" id="03">
        <img src="images/04-the-collector.png" id="04">
      <h1 id="title" class="light">Select a piece below.</h1>

  <div id="portfolio">
    <div class="wrapper">
      <div id="p01" class="item"><a href=""><img src="images/01-after-the-storm-thumb.png" alt="After the Storm preview" /></a></div>
      <div id="p02" class="item"><a href=""><img src="images/02-the-cake-tree-thumb.png" alt="The Cake Tree preview" /></a></div>
      <div id="p03" class="item"><a href=""><img src="images/03-the-great-pumpkin-thumb.png" alt="The Great Pumpkin preview" /></a></div>
      <div id="p04" class="item"><a href=""><img src="images/04-the-collector-thumb.png" alt="The Collector preview" /></a></div>

The portfolio section underneath will contain all of our entry item thumbnails. I’ve linked them into individual div elements with the class .item. The ID attribute is how we can target which image is going to display based on which link is clicked. I have also set the href value of each link to the individual blog post for the items in a scenario where JavaScript is disabled.

Crucial CSS Styles

We can move right along into the short styles.css stylesheet document. This contains all of our default webpage styles and layout formatting. There are just a couple of code blocks which are worth looking over so I’ll point them out here.

/* core body */
#display { 
  display: block; 
  width: 100%; 
  height: 350px; 
  padding: 0px 25px;
  margin-bottom: 35px;
  border-bottom: 1px solid #c5cae1;
  background: #ebedf9 url('images/bg.png') top left repeat;
#portfolio { display: block; width: 100%; padding: 0px 25px; }

.wrapper { margin: 0 auto; max-width: 750px; min-width: 580px; }

The #display and #portfolio divs are containers for the two page sections. I’m using a wrapper class in each area so the content is aligned towards the center with some extra padding. All of the content should be responsive up to the minimum width of 580px.

/* portfolio listing */
#portfolio .item {
	display: block;
	float: left;
  width: 120px;
  height: 65px;
  margin-right: 20px;
  background: none;

#portfolio .item a img {
  -webkit-box-shadow: inset 0 0 3px #fff, 1px 1px 2px rgba(0,0,0,0.4);
  -moz-box-shadow: inset 0 0 3px #fff, 1px 1px 2px rgba(0,0,0,0.4);
  -o-box-shadow: inset 0 0 3px #fff, 1px 1px 2px rgba(0,0,0,0.4);
  box-shadow: inset 0 0 3px #fff, 1px 1px 2px rgba(0,0,0,0.4);
  -webkit-border-radius: 6px;
  -moz-border-radius: 6px;
  -ms-border-radius: 6px;
  -o-border-radius: 6px;
  border-radius: 6px;
  -webkit-transition: all 0.3s linear;
  -moz-transition: all 0.3s linear;
  -o-transition: all 0.3s linear;

#portfolio .item a:hover > img {
  opacity: 0.65;
  filter: Alpha(opacity=65);

The portfolio display properties are a bit more convoluted, but nothing too confusing. Any typical web designer should be able to follow these CSS3 properties for drop shadows and rounded corners. It gives a little kick to the thumbnails gallery and top portfolio display.

Along with all these styles I have also included the Eric Meyer CSS reset customized a bit for this situation. I like to work off his base since it does include all the typical elements you would expect. But if you want to check out the resets just download a copy of my project source code.

Base JavaScript Techniques

With all the other markup out of the way let’s start looking into the JavaScript codes. I have added everything into an external file named script.js. I am working off a single click event handler targeting any of the smaller thumbnail links.

  $("#portfolio .item a").on("click", function(e){
    var clickid  = $(this).parent().attr('id');
    var newimgid = "#"+clickid.slice(1);
    var timer;

All the code we are looking at will be inside the jQuery .on() event handler. First I’m setting the click event to not load the href value. Then I am setting up variables for targeting the clicked element’s ID, along with the new image ID value. Also we need a timer variable so we get the text and image fading at the same time.

Now I have actually defined a couple of JavaScript functions inside of the click event to save space. We are calling the same code repeatedly in various sections of the document, so I added these functions at the very bottom.

    function displayNewImage(img) {
        $(img).fadeIn(500, function() { $(this).addClass("seeme") });
        // set container height to auto so images are responsive
        $("#preview").css("height", "auto");      
    } // end displayNewImage() function
    function displayNewTitle(pid) {
      var newtitle = "";
      if(pid == "p01") { newtitle = "After the Storm"; }      
      if(pid == "p02") { newtitle = "The Cake Tree"; }
      if(pid == "p03") { newtitle = "The Great Pumpkin"; }
      if(pid == "p04") { newtitle = "The Collector"; }      
      $("#title").text(newtitle).fadeIn(230, function() { /* callback */ });      
    }  // end displayNewTitle() function

Now it is much easier to reference loading a new image and text fade effect. Theoretically this action could be pushed into one function call. But for this demonstration I really want to point out the distinction in these methods.

Fading and Dynamic Animations

With the functions in place we can now run a series of effects onto the document every time a user clicks one of the thumbnails. First we need to determine if the page is still blank from the start, or if we have another image already displaying.

In the first scenario we can just go ahead and display our new image. But in the 2nd scenario we need to hide the old image and then display something new. So the codes are very similar but there is an important difference.

    /* if we have another portfolio item displaying then hide it first */
    if($(".seeme").length > 0) {
      // reset conatiner height to keep blank canvas
      $("#preview").css("height", "236px");
      $("#preview .seeme").removeClass("seeme").fadeOut(180, function() {
    /* else nothing is displaying yet and we can just show the image */
    else {
    // hide the title and make text darker if needed
    $("#title").fadeOut(120, function() {
      if($("#title").hasClass("light")) { $("#title").removeClass("light"); }
    // setup new title text and fadeIn
    timer = setTimeout(function() { displayNewTitle(clickid); }, 300);

The if/else logic statement is checking against the current image display. If there are no images with the class .seeme then we know nothing has been displayed yet. Otherwise we hide all the .seeme images(which should only be 1 at a time) and display our new portfolio entry.

Underneath the block of logic we have straight commands to execute the text fading effect. I am using a 300 millisecond delay so the animations are matched close enough together. You could always go into the code and edit this value so the animations appear slower or faster. But having the two functions written in advance is quicker and easier than running duplicate codes.

And an even better point is that visitors who come to your portfolio without JavaScript will not run into problems. Typically the interface would just sit and stall, never loading any images. But without the e.preventDefault() code the thumbnail images will link directly to the original blog post. This is an excellent way to share your portfolio entries while also linking to a live project as a fallback somewhere on the web.

Preview screenshot portfolio jQuery live update panel

Final Thoughts

Hopefully web developers can take away great ideas from this tutorial. Building an online portfolio is not easy and will require time and lots of effort. Don’t get down on yourself for not completing something or understanding an idea as quickly.

Do feel free to play around with my demo example and download a copy of my source code. You may edit this in any way you like and feel free to work with these codes on any project. Additionally if you have any questions or comments on the tutorial feel free to share with us in the discussion area below.

Powered by Shutterstock

About Jake Rocheleau

Jake is a digital researcher and writer on many popular design magazines. He frequently writes on topics including web design, user experience, mobile apps, and project management. You can find him all throughout Google and tweeting @jakerocheleau. Connect with Jake on google+