How to make a navigable & horizontally scrollable portfolio
Posted on Sunday, October 26th, 2008In this short tutorial I’ll be demonstrating how easy it is to create your own horizontal scrolling portfolio. Obviously you can use this effect for things other than a portfolio; you could use it for a short photo gallery, slideshow or a product showcase…
Have a look at the demo to see what I’m talking about.
Download the demo ZIP
I’ll be using jQuery for this tutorial. We won’t need any plugins. Right let’s start!
We’ll start with a basic XHTML document with jQuery, our StyleSheet and our JS file linked to:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Portfolio - Horizontal Scrolling</title> <script type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.2.6.min.js"></script> <script type="text/javascript" src="portfolio.js"></script> <link href="portfolio.css" rel="stylesheet" type="text/css" /> </head> <body> <div id="container"> <!-- Stuff goes here --> </div> </body> </html>
The next step is to markup the portfolio. I’ll be using an unordered list with each of the portfolio pieces as a list item:
<h1>Portfolio</h1> <ul id="portfolio"> <li id="piece1"> <img src="img/1.png" alt="portfolio piece 1 preview" /> <h2>Portfolio piece 1</h2> <p>Lorem ipsum dolor...</p> <p><a href="#">More details »</a></p> </li> <li id="piece2"> <img src="img/2.png" alt="portfolio piece 2 preview" /> <h2>Portfolio piece 2</h2> <p>Lorem ipsum dolor...</p> <p><a href="#">More details »</a></p> </li> <li id="piece3"> <img src="img/3.png" alt="portfolio piece 3 preview" /> <h2>Portfolio piece 3</h2> <p>Lorem ipsum dolor...</p> <p><a href="#">More details »</a></p> </li> <li id="piece4"> <img src="img/4.png" alt="portfolio piece 4 preview" /> <h2>Portfolio piece 4</h2> <p>Lorem ipsum dolor...</p> <p><a href="#">More details »</a></p> </li> <li id="piece5"> <img src="img/5.png" alt="portfolio piece 5 preview" /> <h2>Portfolio piece 5</h2> <p>Lorem ipsum dolor...</p> <p><a href="#">More details »</a></p> </li> <li id="piece6"> <img src="img/6.png" alt="portfolio piece 6 preview" /> <h2>Portfolio piece 6</h2> <p>Lorem ipsum dolor...</p> <p><a href="#">More details »</a></p> </li> <li id="piece7"> <img src="img/7.png" alt="portfolio piece 7 preview" /> <h2>Portfolio piece 7</h2> <p>Lorem ipsum dolor...</p> <p><a href="#">More details »</a></p> </li> <li id="piece8"> <img src="img/8.png" alt="portfolio piece 8 preview" /> <h2>Portfolio piece 8</h2> <p>Lorem ipsum dolor...</p> <p><a href="#">More details »</a></p> </li> <li id="piece9"> <img src="img/9.png" alt="portfolio piece 9 preview" /> <h2>Portfolio piece 9</h2> <p>Lorem ipsum dolor...</p> <p><a href="#">More details »</a></p> </li> <li id="piece10"> <img src="img/10.png" alt="portfolio piece 10 preview" /> <h2>Portfolio piece 10</h2> <p>Lorem ipsum dolor...</p> <p><a href="#">More details »</a></p> </li> </ul>
We’ll also need to add some basic styles: (portfolio.css)
body,ul,li,h1,h2,p,img { margin: 0; padding: 0; list-style: none; border: none; } #container { width: 900px; margin: 0 auto; font-size: 0.8em; font-family: Arial, sans-serif; } h1 { font-size: 2.4em; text-align: center; padding: 30px 0; } h2 { font-size: 1.3em; padding: 0.5em 0; } #portfolio li { overflow: hidden; padding: 10px; margin: 10px 0; } #portfolio li img { float: left; margin: 0 10px 0 0; } #portfolio li p { padding: 0.3em 0 0.5em 0; }
You’ll notice that each portfolio item has an H2 which contains the title, an IMG (which has a preview of the portfolio piece) and a paragraph explaining the portfolio piece. The next step is to extract the required information using jQuery and generate a navigation menu which will allow users to navigate through each slide of the portfolio.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | // portfolio.js $(function(){ // Function initiates when DOM is ready // Apply styles to #portfolio and wrap it in #portfolio-wrapper $('#portfolio') .css({ height: '163px', // 163 is the height of each portfolio piece width: ($(this).width() * $('#portfolio li').size()) + 'px', // i.e. 900x10 = 9000 position: 'relative' }) .wrap('<div id="portfolio-wrapper" style="width:900px;overflow:hidden;position:relative;"></div>'); // Wrap in new DIV element (required for scroll to work properly) $('#portfolio li') // Looping through each list-item: .each(function(){ var newNavItem = addPortfolioNavItem( $(this).attr('id') , $('img:eq(0)',this).attr('src') , $('h2',this).text() ); newNavItem.children('a:eq(0)').click(function(){ // When portfolio nav-item is clicked: $('img',this).css({opacity:0.8}); // Dim to .8 opacity (to show the user they've been there) var id = $(this).attr('href').split('#')[1]; // FIX: IE returns actual HREF instead of href attribute var difference = $('#portfolio').offset().left-$('#portfolio li#' + id).offset().left; // leftOffset of ul#portfolio minus leftOffset of selected portfolio piece $('#portfolio').animate({left: difference}, 700); // Animate to the value of different over 700 milliseconds return false; // prevent default action of links }); }) .css({ width: '880px', // Specify width as 880 (900 minus 10px padding on each side) margin: 0, float: 'left' }); }); function addPortfolioNavItem(id,imgSrc,title) { // If the new navigation menu has NOT been created yet: if(!$('#portfolio-nav').get(0)) { // Test whether nav-menu already exists $('<ul id="portfolio-nav"/>') .insertBefore('#portfolio-wrapper'); // If it does not exist then create it and insert before #portfolio-wrapper (an element which will be created later) } // creates a new list item and appends it to #portfolio-nav return $('<li><a href="#' + id + '" title="' + title + '"><img width="90" src="' + imgSrc + '" alt="' + title + '" /></a></li>').css({display:'inline'}).appendTo('#portfolio-nav'); } |
You’ll see that we’re looping through each list item of the portfolio and then calling the addPortfolioNavItem function which will create a new navigation item and append it to the newly created ul#portfolio-nav (which is inserted into the DOM before ul#portfolio. When one of the thumbnail images (in the navigation menu) is clicked it dims to 0.8 opacity to show the user what slides they’ve already viewed, then it uses jQuery’s animate method to smoothly change the left CSS property of ul#portfolio to match the offset of the selected slide. I hope the comments in the code above are sufficient, if you have any questions feel free to ask below.
The DEMO shows a very basic example of what can be achieved with the above JavaScript, obviously you could achieve something far snazzier with a little bit more CSS…
October 27th, 2008 at 4:36 pm
Nice, but it has a bug. If you quickly click many navigation items it will switch to the first one, then the second one, then to the third one, and so on and so forth instead of just going to the last one you clicked.
October 27th, 2008 at 4:40 pm
Yeh I noticed that, but I see it as a feature, not a bug. If a user clicks multiple times it makes logical sense for it to queue up and then run through the queue progressively. Plus I’d imagine most users won’t be clicking around that quickly…
It’s easily fixable though, just before the
#portfoliois animated its animation queue can be emptied:October 27th, 2008 at 11:31 pm
Really cool
thanks
October 29th, 2008 at 3:01 pm
where is the .zip example???????????? it’s more easy
October 29th, 2008 at 7:15 pm
Glad you like it Sergio!
@maro, what do you mean? If you want to download the source it’s pretty easy - just go to the demo - it’s all there. I might offer it all as a downloadable zip, just haven’t got time at the moment.
October 29th, 2008 at 8:36 pm
@maro - I just added a ZIP file with all the DEMO contents (HERE). Enjoy!
November 10th, 2008 at 12:37 am
I really like your JS skills. You’re sick, you know that?!
Cheers and thanks for this great tut!
November 18th, 2008 at 5:34 pm
There is an issue. If I tab through the page, including some of the “more details” links, then the position of the items is changed. Then when I keydown or click on the “navigation” it shifts all the portfolio items off page.
Basically, it is assuming that the items will be in a certain position but they can be moved when you focus on links and then the js positioning “breaks”.
November 19th, 2008 at 5:51 pm
Andy, thanks!
Will, woah, thank you for pointing that out. Right now I can’t see a solid way of solving this but I’ll try to look into it. Again, thanks for letting me know!
December 11th, 2008 at 5:49 pm
I have made some changes to the js. You can view the changes in firefox, safari (both Mac and PC) but IE 6 & 7 do not work and give an error. I switched back to the original code and still it does not render the top navigation. I am using jQuery 1.2.6
Thanks,
RLC
December 11th, 2008 at 5:53 pm
opps. did not post the website http://www.randycrook.org/timberlakescamp/index.php
December 14th, 2008 at 5:34 pm
thanksss good codes